Featured Posts

ExtJS, Spring MVC 3 and Hibernate 3.5: CRUD DataGrid... This tutorial will walk through how to implement a CRUD (Create, Read, Update, Delete) DataGrid using ExtJS, Spring MVC 3 and Hibernate 3.5. What do we usually want to...

Readmore

ExtJS plugin: PagingToolbarResizer Well, this is my first ExtJS plugin. Though it is not an advanced plugin, I'm very happy and it is a big accomplishment for me! The problem: ExtJS PagingToolbar Component...

Readmore

Hibernate 3 Annotations Tutorial This tutorial will walk through how to implement a hello world project using Hibernate Annotations and MySQL database. Requirements Download and unzip Hibernate Core...

Readmore

My DeveloperWorks: What's life like for a female Java... Just wanted to share with you my interview on Valerie's My developerWorks blog: Interview with Loiane Groner, Java developer in Brazil. I'm very happy, because this interview...

Readmore

Getting started with ExtJS in your J2EE project This tutorial will walk through how to get an Ext JS installation up and running quickly in your java (J2EE) project. Level: Basic This is the screenshot of this tutorial: First,...

Readmore

Loiane Groner Rss

Tutorial: Getting Started with Spring Security

Posted on : 18-01-2010 | By : Loiane | In : Spring, Spring Security

7

This tutorial will cover a basic scenario where it  integrates Spring Security, using database-backed authentication, into an existing Spring web application.

Spring Security is a security framework that provides declarative security for your Spring-based applications. Spring Security provides a comprehensive security solution, handling authentication and authorization, at both the web request level and at the method invocation level. Based on the Spring Framework, Spring Security takes full advantage of dependency injection (DI) and aspect oriented techniques.

Spring Security is also known as Acegi Security (or simply Acegi).

As with anything else related to spring the learning curve on spring-security is just as steep. But once you get the hang of it, it’s easy peasy and you can use the same configuration over and over again in your web apps.

When I started to study Spring Security, I found these suggested steps at Spring Security page.

If you want to configure Spring Security in your web application, follow the steps:

First thing you need to do is to add the jar files in the application classpath. Download Spring Security, and from inside dist folder, copy the following jar files and paste them into your web application lib folder:

  • spring-security-core-2.0.4.jar
  • spring-security-core-tiger-2.0.4.jar
  • spring-security-acl-2.0.4.jar
  • spring-security-taglibs-2.0.4.jar

Also, you need to download Apache Commons Codec: commons-codec-1.3.jar

Now, let’s start with XML configuration.

Web.xml

Insert the following block of code. It should be inserted right after the/context-param end-tag.

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
           /WEB-INF/security-applicationContext.xml
	</param-value>
</context-param>

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

applicationContext-security.xml

Let’s create the applicationContext-security.xml.

I would suggest getting started with the applicationContext-security.xml that is found in the tutorial sample, and trimming it down a bit. Here’s what I got when I trimmed it down:

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

<!--
  - Sample namespace-based configuration
  -
  - $Id: applicationContext-security.xml 3019 2008-05-01 17:51:48Z luke_t $
  -->

<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-2.0.xsd

http://www.springframework.org/schema/security

http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">

	<global-method-security secured-annotations="enabled">
	</global-method-security>

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

    <!--
    Usernames/Passwords are
        rod/koala
        dianne/emu
        scott/wombat
        peter/opal
    -->
    <authentication-provider>
        <password-encoder hash="md5"/>
        <user-service>
            <user name="rod" password="a564de63c2d0da68cf47586ee05984d7" authorities="ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER" />
            <user name="dianne" password="65d15fe9156f9c4bbffd98085992a44e" authorities="ROLE_USER,ROLE_TELLER" />
            <user name="scott" password="2b58af6dddbd072ed27ffc86725d7d3a" authorities="ROLE_USER" />
            <user name="peter" password="22b5c9accc6e1ba628cedc63a72d57f8" authorities="ROLE_USER" />
	    </user-service>
	</authentication-provider>
</beans:beans>

Now, you can try to execute the web application.

If you try to execute the app and get this exception:

SEVERE: Context initialization failed
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/applicationContext-security.xml]; nested exception is java.lang.NoClassDefFoundError: org/aspectj/lang/Signature
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:420)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:149)
	at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:124)
	at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:92)
	at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:123)
	at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:423)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:353)
	at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:255)
	at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:199)
	at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:45)
	at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3764)
	at org.apache.catalina.core.StandardContext.start(StandardContext.java:4216)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1014)
	at org.apache.catalina.core.StandardHost.start(StandardHost.java:736)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1014)
	at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
	at org.apache.catalina.core.StandardService.start(StandardService.java:448)
	at org.apache.catalina.core.StandardServer.start(StandardServer.java:700)
	at org.apache.catalina.startup.Catalina.start(Catalina.java:552)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:295)
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:433)

Download aspectjrt-1.5.4.jar and add it to your application classpath. It will work.

Let’s make some changes in applicationContext-security.xml.

First change: replace the following code

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

for

<http auto-config="true">

    	<!-- Don't set any role restrictions on login.jsp -->
    	<intercept-url pattern="/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" />

    	<!-- Restrict access to ALL other pages -->
        <intercept-url pattern="/**" access="ROLE_USER" />

        <!-- Set the login page and what to do if login fails -->
        <form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=1" />

</http>

The auto-config attribute basically tells spring-security to configure default settings for itself.

The login.jsp is allowed to be access from ANY role.

Rrestricting access to it would mean that no one would be able to reach even the login page.

Note how we are using a jsp instead of a spring managed controller. The login page does not need to be a spring managed controller at all.

We also tell spring-security to restrict access to ALL url’s to only those users who have the role ROLE_USER.

Let’s say you have more than one user role. Mapping URLs to roles is really easy. In your http element, simply put successive elements like this:

<intercept-url pattern="/admin/*.do" access="ROLE_ADMIN"  />
<intercept-url pattern="/manager/*.do" access="ROLE_MANAGER"  />
<intercept-url pattern="/**.do" access="ROLE_USER,ROLE_ADMIN, ROLE_MANAGER"  />

Of course you do not want to put all the usernames and passwords and theirs roles in the applicationContext-security.xml. But how do we tell spring-security to get all user authentication details from the database?

Put the following code in applicationContext-security.xml (replace usernames and passwords block of code)

<!-- Configure the authentication provider -->
<security:authentication-provider>
	<security:jdbc-user-service data-source-ref="dataSource" />
</security:authentication-provider>

This requires that a dataSource be created first.

Now you ask: what does the convention over configuration assume my database tables look like?

You should be aware that the default authentication provider requires the database structure to be in a certain way:

CREATE TABLE users
(
  username character varying(50) NOT NULL,
  "password" character varying(50) NOT NULL,
  enabled boolean NOT NULL,
  CONSTRAINT users_pkey PRIMARY KEY (username)
);

CREATE TABLE authorities
(
  username character varying(50) NOT NULL,
  authority character varying(50) NOT NULL,
  CONSTRAINT fk_authorities_users FOREIGN KEY (username)
      REFERENCES users (username) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
);

CREATE UNIQUE INDEX ix_auth_username
  ON authorities
  USING btree
  (username, authority);

If you want to configure the queries that are used, simply match the available attributes on the jdbc-user-service element to the SQL queries in the Java class referenced above.

For example: You want to simplify tha database schema by adding the user’s role directly to the user table. Let’s modify the xml configuration:

<jdbc-user-service data-source-ref="dataSource"
    authorities-by-username-query="select username,authority from users where username=?"/>

There are a couple other pages that maybe you want to configure.

Access Denied: This is the page the user will see if they are denied access to the site due to lack of authorization (i.e. tried to hit a page that they didn’t have access to hit, even though they were authenticated properly). This is configured as follows:

<http ... access-denied-page="/accessDenied.jsp">
     ...
</http>

Default Target URL: This is where the user will be redirected upon successful login. This can (and probably should) be a page located under Spring control. Configured as follows:

<http ... >
    ...
        <form-login ... default-target-url="/home.do"/>
    ...
</http>

Logout URL: The page where the user is redirected upon a successful logout. This can be a page located under Spring control too (provided that it allows anonymous access):

<http ... >
    ...
    	<logout logout-success-url="/home.do"/>
    ...
</http>

Login Failure URL: Where the user will be sent if there was an authentication failure. Typically this is back to the login form, with a URL parameter, such as:

<http ... >
    ...
        <form-login ... authentication-failure-url="/login.jsp?login_error=1"/>
    ...
</http>

This is what you need to get started with Spring Security.

Next week, I am going to post how Spring Security login.jsp looks like.

Happy coding!

Comments (7)

Dear the Author of this post,

it’s is really good post. It helps me to understand more about Spring security. and now i am trying with this, So can you post the last part. Thanks in advance.

Nice post, but would really like to see the whole article as I’m eagerly following the article.

Hi Ur post has good enough info to start with. I am working on using own User and Authority tables with little more different schema. To mention not I read blog post regarding “Interview with Female Java Developer” and was fascinated and really njoyed it,

Nice article. For those starting out, this is a more advanced tutorial on SpringFramework. I would suggest you check out simple intro first to understand how Spring works.

Nice post BTW

Very nice article…

very good tutorial.
Is it possible to get the login form pop up without redirecting to index.jsp? I have a single page ajax app which I implemented with extjs and it would be much cooler to just get the modal login form (background inactive)

Thanks
Essey

Write a comment