Click here to Skip to main content
Click here to Skip to main content
Go to top

Getting Started Spring Security

, 13 Sep 2011
Rate this:
Please Sign up or sign in to vote.
This article explains the core concepts of Spring Security Namespace Configuration and explains the set up required for a simple form based authentication in a web application.

Introduction

Spring Security is a Java/J2EE framework that provides advanced security features for the enterprise application. This framework was started as an "Acegi Security Framework", later adopted by Spring as its subproject "Spring Security". Spring Security targets two areas namely, Authentication and Authorization. This article explains the concepts of Spring Security and how it is modeled in the framework. This article focuses only on namespace configuration introduced in Spring 2.0. This article assumes that the reader knows the basics of Java and Spring. (This article does not cover all the implementations of the supporting classes, it covers only default implementations that are used by namespace configuration. It also does not cover all the authentication models such as LDAP, CAS. It only covers HTTP Form Based Authentication. In Authorization, it does not cover authorizing access to individual domain object instances such as ACL.)

Spring Security Concepts

Spring Security works around two core areas of security, Authentication and Authorization.

"Authentication" is the assurance that the user is actually the user he is claiming to be, for example, when the user logs into any application and gives his credentials, he authenticates himself. At the authentication level, spring supports various authentication models such as Http Basic authentication, Form Based authentication.

"Authorization" is the assurance that the user is allowed to access only those resources that he is authorized to use. For example, in a corporate application, there are some parts of an application where only admin have access and to some parts all the employees have access. These access rules are determined by the access rights given to each user of the system. At the authorization level, spring targets three main areas: authorizing web request, authorizing whether methods can be invoked and authorizing access to individual domain object instances.

Getting Started

To get started with the implementation, following jars need to be present in the class path of the project.

  • Core - spring-security-core.jar
  • Web - spring-security-web.jar
  • Config - spring-security-config.jar

Namespace Configuration

The namespace configuration of the spring provides lot of shortcuts that hides much of the complexity of the framework. To start with this configuration, define a security filter in web.xml as shown below:

<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>

In the above configuration, DelegatingFilterProxy delegates the control to a filter implementation which is defined as a bean named springSecurityFilterChain. This bean is an infrastructure internal bean to handle namespace configurations. Once this configuration is done, all the incoming requests enter the spring framework for security checks.

Security Configuration

The security configuration is done in XML file and can have any name such as applicationContext-security.xml. This file needs to be loaded explicitly from web.xml. This is done by adding ContextLoadListener. The following lines needs to be added before security filter definition in web.xml.

<context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>WEB-INF/applicationContext-security.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.
	ContextLoaderListener</listener-class>
</listener>

applicationContext-security.xml

When the namespace configuration is used, spring-config.jar needs to be present in the classpath. The first line in this XML file is the schema definition as shown below:

<beans xmlns="http://www.springframework.org/schema/security"
  xmlns:bean="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.3.xsd">
    ...
</beans>

The minimal namespace configuration looks like:

<http auto-config='true'>
 <intercept-url pattern="/**" access="ROLE_USER" />
</http>

<authentication-manager>
    <authentication-provider>
      <user-service>
        <user name="testadmin" password="testadminpassword" 
	authorities="ROLE_USER, ROLE_ADMIN" />
        <user name="testuser" password="testuserpassword" authorities="ROLE_USER" />
      </user-service>
    </authentication-provider>
</authentication-manager> 

The above configuration declares that all the urls in the application will be intercepted for the security checks and the urls can only be accessed by the user with role ROLE-USER. The attribute "auto-config=true" defines three elements <form-login/>, <http-basic/> and <logout>.The default configuration always chooses http-basic authentication model. If the model needs to be changed to the form-login model, then the following configuration is needed.

<http auto-config='true'>
    <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/**" access="ROLE_USER" />
    <form-login login-page='/login.jsp'/></http>

This configuration is done to enable form-login authentication model where the login page is login.jsp. Note that in the intercept tag, pattern for login.jsp is given and access rule is defined as IS_AUTHENTICATED_ANONYMOUSLY. That means login.jsp is not checked for security, which makes sense as login.jsp is the starting point from where the user is authenticated.

The tag <authentication-manager> processes the authentication information; <authentication-provider> defines the credential information and the roles given to each user (authentication information).

The above configuration defines the very minimalistic approach for security. But, when it needs customization according to business requirements, it is very important to understand what happens internally. Spring Security framework is a chain of filters, with each filter having certain responsibility. The next section opens the namespace configuration to bean configuration to understand the flow and responsibility of each filter.

Namespace Configuration to Bean configuration

The <http> block in namespace configuration invokes the chain of filters. DelegatingFilterProxy that is defined in web.xml invokes the FilterChainProxy class which in turn invokes the chain of filters defined for each URL pattern.

The chain of filters that FilterChainProxy calls are shown below:

To define the FilterChainProxy in the applicationContext-security.xml, a bean needs to be defined. This bean can have any name; the only thing to remember is that it should be an alias for bean springSecurityFilterChain defined in web.xml. Change the schema definition to make bean as default.

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:security="http://www.springframework.org/schema/security"
  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.3.xsd">
    ...
</beans>

To define the alias:

<alias name="filterChainProxy" alias="springSecurityFilterChain"/>

The definition of filter chain proxy:

<bean id="filterChainProxy" 
 class="org.springframework.security.web.FilterChainProxy">
   <security:filter-chain-map path-type="ant">
    <security:filter-chain pattern="/login.jsp*" filters="none"/>
    <security:filter-chain pattern="/**" filters=" 
	securityContextFilter, logoutFilter, formLoginFilter, requestCacheFilter,
               servletApiFilter, anonFilter, sessionMgmtFilter, 
		exceptionTranslator, filterSecurityInterceptor" />
   </security:filter-chain-map>  </bean>

The above configuration declares that for URL pattern login.jsp, no filters should be applied and, for all other URL patterns, the filters as shown above should be applied. All these beans should be defined as a bean in the configuration file. All the filters defined in the above configuration are invoked in the same order in which they are defined.

SecurityContextPersistenceFilter (org.springframework.security.web.context)

This filter will be executed only once per request. This filter loads the existing context from the SecurityContextRepository before the request goes to the authentication process; if the context does not exist then it will create a new context. Context is an instance of SecurityContext class which stores the details of the authentication such as credential information, authority assigned to the user. All this information is wrapped in an Authentication object. SecurityContextRepository is a class that holds the context, this information can be stored in the session or in the database or anywhere according to the requirements. The default configuration is HTTP session using HttpSessionSecurityContextRepository. If it needs any customization, then a custom repository can be written by implementing SecurityContextRepository. Once the request is completely processed, filter saves the context information again to the repository. The class diagram looks like:

The configuration of SecurityContextPersistenceFilter is shown below:

<bean id="securityContextFilter" 
class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
   <property name="securityContextRepository" ref=" securityContextRepository "/>
</bean>
<bean id="securityContextRepository"  
class="org.springframework.security.web.context.
HttpSessionSecurityContextRepository" />  

LogoutFilter (org.springframework.security.web.authentication.logout)

This filter is responsible for logging out the user. By default, it invokes only one LogoutHandler i.e., SecurityContextLogoutHandler which clears out the SecurityContext and also invalidates the session if this operation is allowed. Custom handlers can be written by implementing LogoutHandler interface.

The class diagram looks like:

The configuration of LogoutFilter is shown below:

<bean id="logoutFilter" class="org.springframework.
	security.web.authentication.logout.LogoutFilter">
  <constructor-arg value="/logged_out.htm"/>
  <constructor-arg> <list>
       <bean class="org.springframework.security.web.
	authentication.logout.SecurityContextLogoutHandler"/></list>
  </constructor-arg>
</bean>  

UsernamePasswordAuthenticationFilter (org.springframework.security.web.authentication)

This filter performs the authentication process. In the namespace configuration when the form-based authentication is configured, UsernamePasswordAuthenticationFilter is called by default. The name of the parameters it requires and the URL it listens to are all configurable by setting the properties of this class. This filter also requires the AuthenticationManager to be set for doing the authentication process. The possible outcomes of the authentication process are either the user is successfully authenticated or not.

On successful authentication, SavedRequestAwareAuthenticationSuccessHandler is called by default. This handler first checks the original request from the client that is stored in RequestCache and redirects the request to that URI. If "alwaysUseDefaultTargetUrl" property is set, then on successful authentication it is redirected to the default URL. For setting customized URL "targetUrlParameter" property needs to be set. Custom success handler can be written by implementing AuthenticationSuccessHandler interface.

On authentication failure, SimpleUrlAuthenticationFailureHandler is called by default. This handler will check if the property "defaultFailureUrl " is set, if it is set then it will redirect to that URL otherwise it will send 401 response to the client. 401 stands for unauthorized request. There is also a subclass of this handler ExceptionMappingAuthenticationFailureHandler, by using it the exception type is mapped to the URL it should be redirected to. For this, exceptionMapping properties file should be present in a classpath.

The class diagram looks like:

The configuration of UsernamePasswordAuthenticationFilter is shown below:

<bean id="formLoginFilter" 
 class="com.tcs.integrated.internals.security.UsernamePasswordAuthenticationFilter">
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="filterProcessesUrl" value="/j_spring_security_check"/>
  <property name="usernameParameter" value="username "/>
  <property name="passwordParameter" value="password"/>
  <property name="authenticationSuccessHandler">
   <bean class=" 
	org.springframework.security.web.authentication.
	SavedRequestAwareAuthenticationSuccessHandler ">
     <property name="alwaysUseDefaultTargetUrl" value="true"/>
     <property name="defaultTargetUrl" value="/success.jsp"/>
   </bean>
  </property>
  <property name="authenticationFailureHandler">
   <bean class=" org.springframework.security.web.
	authentication.SimpleUrlAuthenticationFailureHandler "/>
  </property>
 </bean>  

In the above configuration, UsernamePasswordAuthenticationFilter is used. This filter will listen to j_spring_security_check for authentication. On successful authentication, SavedRequestAwareAuthenticationSuccessHandler is called which will redirect the user to success.jsp.

AuthenticationManager

AuthenticationManager processes the authentication request. It has various implementations, default is ProviderManager. ProviderManager iterates through a list of AuthenticationProviders. If any of these providers returns a non-null response, user is authenticated successfully. If none of the providers returns non-null response then ProviderNotFoundException is thrown. If all or last provider throw AuthenticationException, then user is not successfully authenticated and gets 401 HTTP status code. There are various implementations of AuthenticationProviders such as DAOAuthenticationProvider. DAOAuthenticationProvider leverages UserDetailsService to look up username, password and GrantedAuthority for a given username from an Authentication request. Some of the implementation of UserDetailsService is JDBCDaoImpl and In-Memory authentication. In-memory authentication is the simplest to configure where the credential information is given in the config file itself as shown below. In JDBCDaoImpl, the information is fetched from the database.

<bean id="authenticationManager" 
class="org.springframework.security.authentication.ProviderManager">
  <property name="providers">
    <list>
      <ref local="daoAuthenticationProvider"/>
      <ref local="anonProvider" />
    </list>
  </property>
</bean>

<bean id="daoAuthenticationProvider" 
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
  <property name="userDetailsService" ref="inMemoryDaoImpl"/>
</bean>

<bean id="inMemoryDaoImpl" 
class=”org.springframework.security.core.userdetails.memory.InMemoryDaoImpl”>
  <property name="userMap">
         <value>test=testpassword,enabled,ROLE_USER</value>
  </property>
</bean>

<bean id="anonProvider"  
class="org.springframework.security.providers.anonymous.
	AnonymousAuthenticationProvider">
     <property name="key" value="myapp" />
</bean>

The above configuration defines an AuthenticationManager implementation ProviderManager which uses two providers DaoAuthenticationProvider and AnonymousProvider. DaoAuthenticationProvider uses InMemoryDaoImpl to fetch the user credential information for a given Authentication request.

RequestCacheAwareFilter (org.springframework.security.web.savedrequest)

This filter fetches the request from the RequestCache, if the current request is found in the cache, then it forwards the wrapped request to the next filter, otherwise the original request is forwarded to the next filter.

The class diagram looks like:

The configuration of RequestCacheAwareFilter is shown below:

<bean id="requestCacheFilter" class="org.springframework.security.
web.savedrequest.RequestCacheAwareFilter" />

SecurityContextHolderAwareRequestFilter(org.springframework.security.web.servletapi)

This filter wraps the ServletRequest with the wrapper that implements security specific method. This is required to access the Authentication details from the request object. When the request is forwarded from a security framework to a Spring MVC framework, this wrapper request object is required to check authorization details. This wrapper implements the following methods:

  • getRemoteUser(): To get the principal's name
  • getUserPrincipal(): To get the Authentication object
  • isUserInRole(): Returns true if user has assigned some role, otherwise false

The class diagram looks like:

The configuration of SecurityContextHolderAwareRequestFilter is shown below:

<bean id="servletApiFilter" class="org.springframework.security.web.
	servletapi.SecurityContextHolderAwareRequestFilter"/>  

AnonymousAuthenticationFilter(org.springframework.security.web.authentication)

This filter populates the authentication object in security context if it is null. This situation comes when for some of the URL the user is not required to get authenticated such as for login.jsp. For such URIs, an anonymous user is defined and an anonymous role is given to it. The definition looks like:

<bean id="anonFilter" 
class="org.springframework.security.web.authentication.
	AnonymousAuthenticationFilter" >
   <property name="key" value="SomeUniqueKeyForThisApplication" />
  <property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS" />
</bean>  

The above configuration declares the anonFilter bean, there are two parameters, key can be anything specific to the application, and this key will be used by AnonymousAuthenticationProvider when processing the authentication. In userAttributes the principle and the authorities granted for this principle is defined. The configuration for AnonymousAuthenticationProvider:

<bean id="anonymousAuthenticationProvider" 
class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
 <property name="key" value="foobar"/>
</bean> 

SessionManagementFilter(org.springframework.security.web.session)

This filter is applied only once per request. With the help of this filter, various session related activity can be performed. Such as, to guard the application from session fixation the sessionID associated with the request can be changed after every successful authentication. SessionFixationProtectionStrategy is a class that performs this change. Or, if application supports concurrent user per session, then ConcurrentSessionControlStrategy is a class that performs the check related to concurrent users. If the number of users allowed per session exceeded then it will throw SessionAuthenticationException, otherwise allows the user to proceed. It needs a SecurityContextRepository to check if the user is authenticated or not. The definition of the bean looks like:

The class diagram looks like:

The configuration of SessionManagementFilter is shown below:

 <bean id="sessionMgmtFilter" 
class="org.springframework.security.web.session.SessionManagementFilter">
    <constructor-arg ref="customSecurityContextRepository"/>
 </bean>   

ExceptionTranslationFilter (org.springframework.security.web.access)

This filter handles AuthenticationException and AccessDeniedException that is thrown from a filter chain. If an AuthenticationException is thrown, it launches the entryPoint defined by its property "authenticationEntryPoint". If AccessDeniedException is thrown and user is an anonymous user then the authenticationEntryPoint is launched. Otherwise, 403 (Access Forbidden) status code is returned by AccessDeniedHandlerImpl.

The class diagram looks like:

The configuration of ExceptionTranslationFilter is shown below:

<bean id="exceptionTranslator" 
class="org.springframework.security.web.access.ExceptionTranslationFilter">
    <property name="requestCache" ref="myRequestCache"/>
     <property name="authenticationEntryPoint">
        <bean class="org.springframework.security.web.authentication.
		LoginUrlAuthenticationEntryPoint">
           <property name="loginFormUrl" value="/login.jsp"/>
        </bean>
     </property>
   </bean>
   <bean id ="myRequestCache" 
     class="org.springframework.security.web.savedrequest.HttpSessionRequestCache">
   </bean>

FilterSecurityInterceptor(org.springframework.security.web.access.intercept)

This interceptor performs the security authorization checks on the request according to the configured parameters. The meta data that is set in this interceptor as shown below declares the URL patterns and the authorization role it needs to access the resources.

The class diagram looks like:

The configuration of FilterSecurityInterceptor is shown below:

<bean id="filterSecurityInterceptor" 
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
 <property name="securityMetadataSource">
  <security:filter-security-metadata-source>
  <security:intercept-url pattern="/user/**" access="ROLE_USER,ROLE_ADMIN"/>
  <security:intercept-url pattern="/login.jsp*" access="ROLE_ANONYMOUS" />
  </security:filter-security-metadata-source>
 </property>
 <property name="accessDecisionManager" ref="accessDecisionManager" />
</bean>

<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>  

The above configuration declares that the request matching the pattern /user/** should be authenticated for roles ROLE_USER or ROLE_ADMIN. Any other URL can access the resource without going through security checks. Note that in filterChainProxy we have defined that for login.jsp filters are bypassed completely. Setting any access value for this login.jsp will have no effect as this interceptor will never be called. Authorization is done with the help of various implementations of AccessDecisionManager. The default is AffirmativeBased that grants access if any AccessDecisionVoter returns an affirmative response. AccessDecisionVoter is having various implementations that are responsible for voting on authorizing decisions. Default is RoleVoter. RoleVoter looks into the meta-data defined in FilterSecurityInterceptor. It first checks that the access defined starts with ROLE_ prefix. If not, then it returns ACCESS_ABSTAIN. Otherwise, it checks that the role defined is same as present in the Authentication object. If it matches, then it returns ACCESS_GRANTED, otherwise, ACCESS_DENIED. Note that all the comparisons are case sensitive.

Conclusion

Spring security framework is a robust and a well defined framework for implementing security requirements. Because of its interface based design, it is highly customizable. This article only touches the default configuration of the security framework. Default configurations help to understand the basics which are very crucial to customize this framework according to specific requirements.

History

  • 12th September, 2011: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

No Biography provided

Comments and Discussions

 
GeneralThe best Spring article I've read. Pinmemberavijendr25-Feb-14 14:42 
Generalthank PinmemberSurasak Khammuangsri9-Jan-14 20:34 
GeneralMy vote of 4 PinmemberSudhakar Shinde18-Apr-13 2:57 
QuestionGreat article! [modified] Pinmemberjosecarlosmissias1-Dec-11 2:01 
GeneralGood work PinmemberVinayakIyer23-Sep-11 2:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140926.1 | Last Updated 13 Sep 2011
Article Copyright 2011 by Diptee Warudkar Dalal
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid