Monday 18 March 2013

Spring Security 3.1.0 using database and form login (STS IDE is used)

Spring Security Introduction

Authentication is performed against user name and password.

Authorization is performed after authentication.Used when We want only authenticated users with particular roles to allow access to particular URL.

1. XML Based Spring authorization and authentication.

2. various ways of authorization and authentication can be performed.

like database,LDAP,Single sign on, memory based.

3. Remember me can be configured using spring.

4. It is good to configure security in spring as much possible rather than on tomcat. Because migration of project from one server to another doesnt require reconfigure security. Spring Security are migrated with war.

5. Spring locates all spring related xml from web.xml. We have  add spring filter in web.xml
 <!-- 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>


<param-value>/WEB-INF/spring/root-context.xml,
                       /WEB-INF/spring-database.xml,
            /WEB-INF/spring-security.xml
            </param-value>


7. We can configure in spring which url to intercept and perform authentication and which to all access.

<http auto-config="true"  >
        <intercept-url pattern="/"   access="ROLE_USER"/>
        <form-login login-page="/login" default-target-url="/welcome"
            authentication-failure-url="/loginfailed" />
        <logout logout-success-url="/logout" />
              
    </http>

8. Spring gets authentication and authorization information by below configuration

<authentication-manager>
        <authentication-provider>
            <jdbc-user-service data-source-ref="dataSource"
               
                users-by-username-query="
                    select username,password, enabled
                    from users where USERNAME=?"
               
                authorities-by-username-query="
                    select u.username, ur.authority from users u, user_roles ur
                    where u.user_id = ur.user_id and u.username =?  "
                   
            />
        </authentication-provider>

below I have described the structure of tables used by spring.

9. I have used controller that receives request and perform logical operation and forwards request to particular jsp configured in servlet-context.xml


Full documentation of spring security is available in spring official website.


1. From STS select Spring template Project. click next . select Spring MVC Project. Enter Project Name and top level package name as shown in image. Than click finish






 2.
 Update you pom.xml to include below dependency

<!-- MySQL database driver -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.9</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>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>


3. Update your web.xml to include filter of spring and xml of spring

<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/root-context.xml,
                       /WEB-INF/spring-database.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>


4. My SQL Dump



CREATE DATABASE IF NOT EXISTS logintest;
USE logintest;


DROP TABLE IF EXISTS `user_roles`;
CREATE TABLE `user_roles` (
  `USER_ROLE_ID` int(10) unsigned NOT NULL,
  `USER_ID` int(10) unsigned NOT NULL,
  `AUTHORITY` varchar(45) NOT NULL,
  PRIMARY KEY (`USER_ROLE_ID`),
  KEY `FK_user_roles` (`USER_ID`),
  CONSTRAINT `FK_user_roles` FOREIGN KEY (`USER_ID`) REFERENCES `users` (`USER_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO `user_roles` (`USER_ROLE_ID`,`USER_ID`,`AUTHORITY`) VALUES
 (1,100,'ROLE_USER');



DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `USER_ID` int(10) unsigned NOT NULL,
  `USERNAME` varchar(45) NOT NULL,
  `PASSWORD` varchar(45) NOT NULL,
  `ENABLED` tinyint(1) NOT NULL,
  PRIMARY KEY (`USER_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


5. Spring Database configuration src\main\webapp\WEB-INF\spring-database.xml

Spring framework locate this file from context parameter defined in web.xml

spring-database.xml
<beans xmlns="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">

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">

        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/loginTest" />
        <property name="username" value="root" />
        <property name="password" value="root" />
    </bean>

</beans>


6. Spring Security configuration src\main\webapp\WEB-INF\spring-security.xml

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 pattern="/"   access="ROLE_USER"/>
        <form-login login-page="/login" default-target-url="/welcome"
            authentication-failure-url="/loginfailed" />
        <logout logout-success-url="/logout" /> 
    </http>

    <authentication-manager>
        <authentication-provider>
            <jdbc-user-service data-source-ref="dataSource"
               
                users-by-username-query="
                    select username,password, enabled
                    from users where USERNAME=?"
               
                authorities-by-username-query="
                    select u.username, ur.authority from users u, user_roles ur
                    where u.user_id = ur.user_id and u.username =?  "
                   
            />
        </authentication-provider>
    </authentication-manager>


</beans:beans>


7. Create JSP inside src\main\webapp\WEB-INF\views

hello.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<body>
    <h3>Message : ${message}</h3>   
    <h3>Username : ${username}</h3>   
   
    <a href="<c:url value="/j_spring_security_logout" />" > Logout</a>
   
</body>
</html>

login.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>Login Page</title>
<style>
.errorblock {
    color: #ff0000;
    background-color: #ffEEEE;
    border: 3px solid #ff0000;
    padding: 8px;
    margin: 16px;
}
</style>
</head>
<body onload='document.f.j_username.focus();'>
    <h3>Login with Username and Password (Authentication with Database)</h3>

    <c:if test="${not empty error}">
        <div class="errorblock">
            Your login attempt was not successful, try again.<br /> Caused :
            ${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
        </div>
    </c:if>

    <form name='f' action="<c:url value='j_spring_security_check' />"
        method='POST'>

        <table>
            <tr>
                <td>User:</td>
                <td><input type='text' name='j_username' value=''>
                </td>
            </tr>
            <tr>
                <td>Password:</td>
                <td><input type='password' name='j_password' />
                </td>
            </tr>
            <tr>
                <td colspan='2'><input name="submit" type="submit"
                    value="submit" />
                </td>
            </tr>
            <tr>
                <td colspan='2'><input name="reset" type="reset" />
                </td>
            </tr>
        </table>

    </form>
</body>
</html>

8. Create Login Controller. It receives request and process it and forwards request to JSP.

LoginController.java

package com.milan.myLogin;


import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class LoginController {

    @RequestMapping(value="/welcome", method = RequestMethod.GET)
    public String printWelcome(ModelMap model) {

        User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String name = user.getUsername();
   
        model.addAttribute("username", name);
        model.addAttribute("message", "Spring Security login + database example");
        return "hello";

    }

    @RequestMapping(value="/login", method = RequestMethod.GET)
    public String login(ModelMap model) {

        return "login";

    }
   
    @RequestMapping(value="/loginfailed", method = RequestMethod.GET)
    public String loginerror(ModelMap model) {

        model.addAttribute("error", "true");
        return "login";

    }
   
    @RequestMapping(value="/logout", method = RequestMethod.GET)
    public String logout(ModelMap model) {

        return "login";

    }
   
}



Let me know if you found this post usefull.

Author
Milan D Ashara