Basic configuration of Spring Security 3

In this post I write about a basic configuration of Spring Security 3, the Spring framework for authentication and authorization of the users.
In this example there is only one user trying to access to index.html and he is redirected to the standard login page for authentication.
In this project I use and configure maven and log4j too.

  1. create the project SpringSecurity
  2. create the file pom.xml
    <project
    	xmlns="http://maven.apache.org/POM/4.0.0"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    	<groupId>SpringSecurity</groupId>
    	<artifactId>SpringSecurity</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<packaging>war</packaging>
    
    	<!-- Shared version number properties -->
    	<properties>
    		<org.springframework.version>3.1.1.RELEASE</org.springframework.version>
    		<log4j.version>1.2.17</log4j.version>
    		<jstl.version>1.2</jstl.version>
    	</properties>
    
    	<dependencies>
    
    		<!-- Core utilities used by other modules. Define this if you use Spring 
    			Utility APIs (org.springframework.core.*/org.springframework.util.*) -->
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-core</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<!-- Expression Language (depends on spring-core) Define this if you use 
    			Spring Expression APIs (org.springframework.expression.*) -->
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-expression</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<!-- Bean Factory and JavaBeans utilities (depends on spring-core) Define 
    			this if you use Spring Bean APIs (org.springframework.beans.*) -->
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-beans</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<!-- Aspect Oriented Programming (AOP) Framework (depends on spring-core, 
    			spring-beans) Define this if you use Spring AOP APIs (org.springframework.aop.*) -->
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-aop</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<!-- Application Context (depends on spring-core, spring-expression, spring-aop, 
    			spring-beans) This is the central artifact for Spring's Dependency Injection 
    			Container and is generally always defined -->
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-context</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<!-- Various Application Context utilities, including EhCache, JavaMail, 
    			Quartz, and Freemarker integration Define this if you need any of these integrations -->
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-context-support</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<!-- Transaction Management Abstraction (depends on spring-core, spring-beans, 
    			spring-aop, spring-context) Define this if you use Spring Transactions or 
    			DAO Exception Hierarchy (org.springframework.transaction.*/org.springframework.dao.*) -->
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-tx</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<!-- JDBC Data Access Library (depends on spring-core, spring-beans, spring-context, 
    			spring-tx) Define this if you use Spring's JdbcTemplate API (org.springframework.jdbc.*) -->
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-jdbc</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<!-- Object-to-Relation-Mapping (ORM) integration with Hibernate, JPA, 
    			and iBatis. (depends on spring-core, spring-beans, spring-context, spring-tx) 
    			Define this if you need ORM (org.springframework.orm.*) -->
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-orm</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<!-- Object-to-XML Mapping (OXM) abstraction and integration with JAXB, 
    			JiBX, Castor, XStream, and XML Beans. (depends on spring-core, spring-beans, 
    			spring-context) Define this if you need OXM (org.springframework.oxm.*) -->
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-oxm</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<!-- Web application development utilities applicable to both Servlet and 
    			Portlet Environments (depends on spring-core, spring-beans, spring-context) 
    			Define this if you use Spring MVC, or wish to use Struts, JSF, or another 
    			web framework with Spring (org.springframework.web.*) -->
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-web</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<!-- Spring MVC for Servlet Environments (depends on spring-core, spring-beans, 
    			spring-context, spring-web) Define this if you use Spring MVC with a Servlet 
    			Container such as Apache Tomcat (org.springframework.web.servlet.*) -->
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-webmvc</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<!-- Spring MVC for Portlet Environments (depends on spring-core, spring-beans, 
    			spring-context, spring-web) Define this if you use Spring MVC with a Portlet 
    			Container (org.springframework.web.portlet.*) -->
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-webmvc-portlet</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<!-- Support for testing Spring applications with tools such as JUnit and 
    			TestNG This artifact is generally always defined with a 'test' scope for 
    			the integration testing framework and unit testing stubs -->
    		<dependency>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-test</artifactId>
    			<version>${org.springframework.version}</version>
    			<scope>test</scope>
    		</dependency>
    
    		<!-- log4j -->
    		<dependency>
    			<groupId>log4j</groupId>
    			<artifactId>log4j</artifactId>
    			<version>${log4j.version}</version>
    		</dependency>
    
    		<!-- Spring Security -->
    		<dependency>
    			<groupId>org.springframework.security</groupId>
    			<artifactId>spring-security-core</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<dependency>
    			<groupId>org.springframework.security</groupId>
    			<artifactId>spring-security-web</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<dependency>
    			<groupId>org.springframework.security</groupId>
    			<artifactId>spring-security-config</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    		<!-- JSTL -->
    		<dependency>
    			<groupId>jstl</groupId>
    			<artifactId>jstl</artifactId>
    			<version>${jstl.version}</version>
    		</dependency>
    
    		<!-- spring security tag -->
    		<dependency>
    			<groupId>org.springframework.security</groupId>
    			<artifactId>spring-security-taglibs</artifactId>
    			<version>${org.springframework.version}</version>
    		</dependency>
    
    	</dependencies>
    
    </project>
    

    In the section “properties” I set the versions of the dependencies; in the comments you read the name of the dependencies: the first part covers the Spring Framework, followed by Log4j for log management, Spring Security for authentication and authorization of the users, jstl or java standard tag library to use the tag “c” (for example <c:if>) and spring security tags to use the tag “sec” (for example <sec:authorize>);
    alternatively you can copy the following files. jar in the directory WEB-INF/lib

    • spring-core-3.1.1.RELEASE.jar
    • spring-asm-3.1.1.RELEASE.jar
    • commons-logging-1.1.1.jar
    • spring-expression-3.1.1.RELEASE.jar
    • spring-beans-3.1.1.RELEASE.jar
    • spring-aop-3.1.1.RELEASE.jar
    • aopalliance-1.0.jar
    • spring-context-3.1.1.RELEASE.jar
    • spring-context-support-3.1.1.RELEASE.jar
    • spring-tx-3.1.1.RELEASE.jar
    • spring-jdbc-3.1.1.RELEASE.jar
    • spring-orm-3.1.1.RELEASE.jar
    • spring-oxm-3.1.1.RELEASE.jar
    • commons-lang-2.5.jar
    • spring-web-3.1.1.RELEASE.jar
    • spring-webmvc-3.1.1.RELEASE.jar
    • spring-webmvc-portlet-3.1.1.RELEASE.jar
    • spring-test-3.1.1.RELEASE.jar
    • log4j-1.2.17.jar
    • spring-security-core-3.1.1.RELEASE.jar
    • spring-security-web-3.1.1.RELEASE.jar
    • spring-security-config-3.1.1.RELEASE.jar
    • jstl-1.2.jar
    • spring-security-taglibs-3.1.1.RELEASE.jar
    • spring-security-acl-3.1.1.RELEASE.jar
  3. create the file WEB-INF/web.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        version="2.5"
        xmlns="http://java.sun.com/xml/ns/javaee"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" >
    
        <display-name>
    		SpringSecurity
        </display-name>
    
        <!-- Spring MVC -->
    
        <servlet>
            <servlet-name>
    			SpringSecurity
            </servlet-name>
            <servlet-class>
    			org.springframework.web.servlet.DispatcherServlet
            </servlet-class>
            <load-on-startup>
    			1
            </load-on-startup>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>
    			SpringSecurity
            </servlet-name>
            <url-pattern>
    			*.html
            </url-pattern>
        </servlet-mapping>
    
        <listener>
            <listener-class>
    			org.springframework.web.context.ContextLoaderListener
            </listener-class>
        </listener>
    
        <context-param>
            <param-name>
    			contextConfigLocation
            </param-name>
            <param-value>
    			/WEB-INF/SpringSecurity-servlet.xml
    			/WEB-INF/spring-security.xml
            </param-value>
        </context-param>
    
        <!-- Spring Security -->
        
        <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>
    
        <!-- Log4j -->
        
        <context-param>
            <param-name>
    			log4jConfigLocation
            </param-name>
            <param-value>
    			/WEB-INF/log4j.xml
            </param-value>
        </context-param>
    
        <listener>
            <listener-class>
                org.springframework.web.util.Log4jConfigListener
            </listener-class>
        </listener>
    
        <session-config>
            <session-timeout>
                30
            </session-timeout>
        </session-config>
    
        <welcome-file-list>
            <welcome-file>
    			index.html
            </welcome-file>
        </welcome-file-list>
    
    </web-app>
    

    You can see the reference to /WEB-INF/spring-security.xml and the sections “filter” and “filter-mapping” to configure Spring Security

  4. create the file WEB-INF/SpringSecurity-servlet.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <beans
    	xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:p="http://www.springframework.org/schema/p"
    	xmlns:context="http://www.springframework.org/schema/context"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
    	<context:component-scan base-package="eu.lucazanini.springsecurity" />
    
    	<bean
    		id="viewResolver"
    		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    		<property name="prefix">
    			<value>/WEB-INF/views/</value>
    		</property>
    		<property name="suffix">
    			<value>.jsp</value>
    		</property>
    	</bean>
    
    </beans>
    
  5. create the file WEB-INF/log4j.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE log4j:configuration PUBLIC "-//LOGGER" "log4j.dtd">
    
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> 
        <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="%d %-5p %c{1}:%L %m %n" />
    <!--
    ConversionPattern format specification
    %d      inserts the date; you can specify the format (%d{yyyy-MM-dd HH:mm:ss,SSS})
    %-5p    inserts the priority log level, 5 characters, left justified
    %c{1}   inserts the name of the class
    %L      inserts the line number
    %m      inserts the user message
    %n      inserts the separator (for example, a new line)
    -->
            </layout>
        </appender>
    
        <appender name="fileAppender" class="org.apache.log4j.RollingFileAppender">
            <param name="Threshold" value="INFO" />
            <param name="MaxFileSize" value="512KB" />
            <param name="MaxBackupIndex" value="10" />
            <param name="File" value="${webapp.root}/WEB-INF/logs/springsecurity.log"/>
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="%d %-5p %c{1}:%L %m %n" />
            </layout>
        </appender>
    
    <!--sets the priority log level for org.springframework-->
        <logger name="org.springframework">
            <level value="info"/>
        </logger>
    
    <!--sets the priority log level for eu.lucazanini.springsecurity-->
        <logger name= "eu.lucazanini.springsecurity">
            <level value="debug"/>
        </logger>
    
    <!--sets the default priority log level-->
        <root>
            <priority value="info"></priority>
            <appender-ref ref="stdout"/>
            <appender-ref ref="fileAppender"/>
        </root>
    </log4j:configuration>
    
  6. create the file WEB-INF/spring-security.xml
    <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.1.xsd">
    
        <http auto-config="true" >
    
            <intercept-url
                access="ROLE_USER"
                pattern="/**" />
        </http>
    
        <beans:bean
            id="encoder"
            class="org.springframework.security.crypto.password.StandardPasswordEncoder" />
    
        <authentication-manager>
    
            <authentication-provider>
    
                <password-encoder ref="encoder" />
                
                <user-service>
    
                    <user
                        name="user"
                        authorities="ROLE_USER"
                        password="20331ba9c4935517ab16f0052097b0d79f40f0a54a1a025ec742a308e8564757e021797bf7185332" />
    
                </user-service>
            </authentication-provider>
        </authentication-manager>
    
    </beans:beans>
    

    The password is encrypted using Scala
    I write the procedure to get the encrypted password:

    • download spring-security-core-*.jar (for example spring-security-core-3.1.1.RELEASE.jar) in the last release of Spring Security
    • install Scala
    • open a console and type:
      scala -cp [your path]/spring-security-core-3.1.1.RELEASE.jar

      where [your path] è is the path to spring-security-core-3.1.1.RELEASE .jar
      (the output should be:
      Welcome to Scala version 2.9.1.r0-b20120114224707 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_05).
      Type in expressions to have them evaluated.
      Type :help for more information.
      )

    • type:
      val encoder = new org.springframework.security.crypto.password.StandardPasswordEncoder

      Output:
      encoder: org.springframework.security.crypto.password.StandardPasswordEncoder = org.springframework.security.crypto.password.StandardPasswordEncoder@448d5117

    • type:
      encoder.encode("spring")

      Output:
      res0: java.lang.String = 20331ba9c4935517ab16f0052097b0d79f40f0a54a1a025ec742a308e8564757e021797bf7185332
      the sequence of charachters after “res0: java.lang.String =” is just the encrypted password in the file spring-security.xml

  7. create the file WEB-INF/views/index.jsp
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
    <html>
    <body>
    	<h1>Spring Security basic configuration</h1>
    	<h3><br />Hello ${username}, ${message}</h3>
    	<sec:authorize ifAnyGranted="ROLE_USER">
            <h6><br />Your role is ROLE_USER</h6>
        </sec:authorize>
    	
    	<input type="button" value="Log out" onClick="location.href='<c:url value="/j_spring_security_logout" />'"/>
    
    </body>
    </html>
    

    I set the variables ${message} and ${username} in LoginController.java; the button is just a link to /j_spring_security_logout and allows the user to log out

  8. create the file WEB-INF/classes/eu/lucazanini/springsecurity/LoginController.java
    package eu.lucazanini.springsecurity;
    
    import java.security.Principal;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.ModelMap;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.apache.log4j.Logger;
    
    @Controller
    public class LoginController {
    
        private static org.apache.log4j.Logger log = Logger
    	    .getLogger(LoginController.class);
    
        @RequestMapping(value = "/index", method = RequestMethod.GET)
        public String printWelcome(ModelMap model, Principal principal) {
    
    	log.debug("LoginController");
    	String name = principal.getName();
    	model.addAttribute("username", name);
    	model.addAttribute("message", "you are logged in");
    
    	return "index";
    
        }
    
    }
    
  9. launch the application (type “user” and “spring”)

References:
Spring Security


Comments

6 responses to “Basic configuration of Spring Security 3”

  1. hansli Avatar

    Thanks for the tutorial!

    May I ask why not use
    encoder = new org.springframework.security.crypto.password.StandardPasswordEncoder;
    encoder.encode(“spring”);

    directly in java , but instead install scala to call the above?

    1. Luca Zanini Avatar
      Luca Zanini

      I need the encrypted password to put in xml file.
      This is the only reason I use Scala, but you can use a standalone java program if you want.

      1. hansli Avatar

        I do see the output from scala+StandardPasswordEncoder is different from java StandardPasswordEncoder, I am confused, since when the web application runs it just needs StandardPasswordEncoder to encode the user submitted password.

        1. Luca Zanini Avatar
          Luca Zanini

          The encode method returns a different output every time even if you use the same password.
          See this
          A standard PasswordEncoder implementation that uses SHA-256 hashing with 1024 iterations and a random 8-byte random salt value

  2. Nice for starting, I was trying to find a simple example to understand the basic configuration. Thanks a lot!!
    Can you provide, if it is possible an example with a CAS server…….
    Thanks

  3. […] this post I explain how to implement Spring Security in a web application, as I did in a previous post but the authenticated user’s username and password are not saved to a file .xml but in a […]

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.