Java and J2EE Tutorials, Jsp and Servlet Tutorials, Spring MVC, Solr, XML, JSON Examples, Hibernate & Struts 2 Hello World projects



Sunday, 31 August 2014

Spring Security with Hibernate using Maven - Authentication and Authorization Example

In our previous discussions we came across a number of implementations in Spring Security, What is Spring Security, Login & Logout with Spring Security, Spring Security Authentication and Authorization

In this particular blog we will see how to configure Spring Security with Hibernate to accomplish Authentication and Authorization in our application. We will use a maven web project for the purpose, we have just created a simple maven web project and imported it in Eclipse.

More Details on : Dynamic Web Project with Maven and Import it in eclipse


Database Setup for Spring Security and Hibernate Integration

Before we go forward let's first create a database and required tables to store and get user credential from, we have created two tables "users" and "user_roles". We have added two users details, with ROLE_USER and ROLE_ADMIN to be used here. Just copy and execute the below script in your mysql query editor to get a db setup for you.

-- Dumping database structure for spring_social_db
CREATE DATABASE IF NOT EXISTS `spring_social_db` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE `spring_social_db`;


-- Dumping structure for table spring_social_db.users
CREATE TABLE IF NOT EXISTS `users` (
  `username` varchar(45) NOT NULL,
  `enabled` bit(1) NOT NULL,
  `password` varchar(60) NOT NULL,
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- Dumping data for table spring_social_db.users: ~2 rows (approximately)
/*!40000 ALTER TABLE `users` DISABLE KEYS */;
INSERT INTO `users` (`username`, `enabled`, `password`) VALUES
 ('admin', b'10000000', 'admin@123'),
 ('user', b'10000000', 'user@123');
/*!40000 ALTER TABLE `users` ENABLE KEYS */;


-- Dumping structure for table spring_social_db.user_roles
CREATE TABLE IF NOT EXISTS `user_roles` (
  `user_role_id` int(11) NOT NULL AUTO_INCREMENT,
  `role` varchar(45) NOT NULL,
  `username` varchar(45) NOT NULL,
  PRIMARY KEY (`user_role_id`),
  KEY `FK_9ry105icat2dux14oyixybw9l` (`username`),
  CONSTRAINT `FK_9ry105icat2dux14oyixybw9l` FOREIGN KEY (`username`) REFERENCES `users` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;

-- Dumping data for table spring_social_db.user_roles: ~3 rows (approximately)
/*!40000 ALTER TABLE `user_roles` DISABLE KEYS */;
INSERT INTO `user_roles` (`user_role_id`, `role`, `username`) VALUES
 (1, 'ROLE_ADMIN', 'admin'),
 (2, 'ROLE_USER', 'user'),
 (3, 'ROLE_USER', 'admin');
/*!40000 ALTER TABLE `user_roles` ENABLE KEYS */;
/*!40014 SET FOREIGN_KEY_CHECKS=1 */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

If everything goes right you will see following table structures.




Dependencies required for Spring Security with Hibernate integration

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/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.beingjavaguys.sample</groupId>
 <artifactId>SP_SC_Hibernate</artifactId>
 <packaging>war</packaging>
 <version>1.0-SNAPSHOT</version>
 <name>SP_SC_Hibernate Maven Webapp</name>
 <url>http://maven.apache.org</url>
 <properties>
  <spring.version>4.0.6.RELEASE</spring.version>
  <hibernate.version>4.3.6.Final</hibernate.version>
  <log4j.version>1.2.17</log4j.version>
  <jdk.version>1.7</jdk.version>
  <jstl.version>1.2</jstl.version>
  <mysql_connector.version>5.1.6</mysql_connector.version>
  <spring.security.version>3.2.5.RELEASE</spring.security.version>
  <context.path>SP_SC_Hibernate</context.path>
 </properties>
 <build>
  <finalName>${pom.artifactId}</finalName>
  <plugins>
   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
     <source>${jdk.version}</source>
     <target>${jdk.version}</target>
    </configuration>
   </plugin>
  </plugins>
 </build>
 <dependencies>

  <!-- hibernate -->
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-entitymanager</artifactId>
   <version>${hibernate.version}</version>
  </dependency>

  <!-- log4j -->
  <dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>${log4j.version}</version>
  </dependency>

  <!-- Spring -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-orm</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-jdbc</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${spring.version}</version>
  </dependency>

  <!-- Spring Security -->
  <dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-web</artifactId>
   <version>${spring.security.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-config</artifactId>
   <version>${spring.security.version}</version>
  </dependency>

  <!-- Spring Security JSP Taglib -->
  <dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-taglibs</artifactId>
   <version>${spring.security.version}</version>
  </dependency>

  <!-- jstl -->
  <dependency>
   <groupId>jstl</groupId>
   <artifactId>jstl</artifactId>
   <version>${jstl.version}</version>
  </dependency>

  <!-- mysql driver -->
  <dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>${mysql_connector.version}</version>
  </dependency>
 </dependencies>
</project>




\src\main\webapp\WEB-INF\web.xml
We need to make an Spring entry to web.xml, this will tell the container that all upcoming requests will be served by Spring Framework itself as per the configuration. We have also added a filter entry to integrate spring security in the application.
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
       http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 version="2.5">

 <display-name>Sample Spring Maven Project</display-name>
<!-- Spring MVC -->  
  
    <servlet>  
        <servlet-name>mvc-dispatcher</servlet-name>  
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
        <load-on-startup>1</load-on-startup>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>mvc-dispatcher</servlet-name>  
        <url-pattern>/</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/mvc-dispatcher-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>

</web-app>


\src\main\webapp\WEB-INF\spring-config.xml
This is simple spring configuration file, we have added entry for base-package here to search and find Controller, Dao and Service classes with annotations. We defined few beans here for hibernate configurations and a datasource bean to connect with database.

More details on : Spring Hibernate Integration
<?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:context="http://www.springframework.org/schema/context"
 xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

 <context:component-scan base-package="com.beingjavaguys" />
 <context:property-placeholder location="classpath:database.properties" />
 <mvc:resources mapping="/resources/**" location="/resources/" />
 <mvc:annotation-driven />

 <bean id="dataSource"
  class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName" value="${database.driver}" />
  <property name="url" value="${database.url}" />
  <property name="username" value="${database.user}" />
  <property name="password" value="${database.password}" />
 </bean>

 <bean id="sessionFactory"
  class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="annotatedClasses">
   <list>
    <value>com.beingjavaguys.models.login.Users</value>
    <value>com.beingjavaguys.models.login.UserRole</value>
   </list>
  </property>
  <property name="hibernateProperties">
   <props>
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
    <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
    <prop key="hibernate.hbm2ddl.auto">update</prop>
   </props>
  </property>
 </bean>

 <bean id="txManager"
  class="org.springframework.orm.hibernate4.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory" />
 </bean>

 <bean id="persistenceExceptionTranslationPostProcessor"
  class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

 <bean
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix">
   <value>/WEB-INF/pages/</value>
  </property>
  <property name="suffix">
   <value>.jsp</value>
  </property>
 </bean>
</beans>

Spring security configuration file

\src\main\webapp\WEB-INF\spring-security.xml

Here is spring-security configuration file with all required configurations and settings, we have defioned two roles here and a service "loginService" bean to communicate with data layer of the application.
<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.2.xsd">

 <!-- enable use-expressions -->
 <http auto-config="true" use-expressions="true">
  <intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')" />
  <intercept-url pattern="/user**" access="hasRole('ROLE_USER')" />

  <!-- access denied page -->
  <access-denied-handler error-page="/403" />
  <form-login login-page="/login" authentication-failure-url="/login?error"
   username-parameter="username" password-parameter="password" />
  <logout logout-success-url="/login?logout" />
  <!-- enable csrf protection -->
  <csrf />
 </http>

 <authentication-manager>
  <authentication-provider user-service-ref="loginService" />
 </authentication-manager>

</beans:beans>


Login controller code

\src\main\java\com\beingjavaguys\controller\LoginController.java

This is simple spring mvc controller having request mappings to deal with different incoming request and render appropriate pages used in the login process.
package com.beingjavaguys.controller;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.beingjavaguys.models.login.Users;

@Controller
public class LoginController {

 @RequestMapping(value = { "/", "/home" })
 public String getUserDefault() {
  return "home";
 }

 @RequestMapping("/login")
 public ModelAndView getLoginForm(@ModelAttribute Users users,
   @RequestParam(value = "error", required = false) String error,
   @RequestParam(value = "logout", required = false) String logout) {

  String message = "";
  if (error != null) {
   message = "Incorrect username or password !";
  } else if (logout != null) {
   message = "Logout successful !";
  }
  return new ModelAndView("login", "message", message);
 }

 @RequestMapping("/admin**")
 public String getAdminProfile() {
  return "admin";
 }

 @RequestMapping("/user**")
 public String getUserProfile() {
  return "user";
 }

 @RequestMapping("/403")
 public ModelAndView getAccessDenied() {
  Authentication auth = SecurityContextHolder.getContext()
    .getAuthentication();
  String username = "";
  if (!(auth instanceof AnonymousAuthenticationToken)) {
   UserDetails userDetail = (UserDetails) auth.getPrincipal();
   username = userDetail.getUsername();
  }

  return new ModelAndView("403", "username", username);
 }

}



Model classes to represent "user" and "user_role" tables in database

\src\main\java\com\beingjavaguys\models\login\Users.java

package com.beingjavaguys.models.login;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "users", catalog = "spring_social_db")
public class Users {

 @Id
 @Column(name = "username", unique = true, nullable = false, length = 45)
 private String username;

 @Column(name = "password", nullable = false, length = 60)
 private String password;

 @Column(name = "enabled", nullable = false)
 private boolean enabled;

 @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
 private Set userRole = new HashSet(0);

 
 public String getUsername() {
  return username;
 }

 public void setUsername(String username) {
  this.username = username;
 }

 public String getPassword() {
  return password;
 }

 public void setPassword(String password) {
  this.password = password;
 }

 public boolean isEnabled() {
  return enabled;
 }

 public void setEnabled(boolean enabled) {
  this.enabled = enabled;
 }

 public Set getUserRole() {
  return userRole;
 }

 public void setUserRole(Set userRole) {
  this.userRole = userRole;
 }
}


\src\main\java\com\beingjavaguys\models\login\UserRole.java
package com.beingjavaguys.models.login;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "user_roles", catalog = "spring_social_db")
public class UserRole {

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 @Column(name = "user_role_id", unique = true, nullable = false)
 private Integer userRoleId;

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "username", nullable = false)
 private Users user;

 @Column(name = "role", nullable = false, length = 45)
 private String role;

 public Integer getUserRoleId() {
  return userRoleId;
 }

 public void setUserRoleId(Integer userRoleId) {
  this.userRoleId = userRoleId;
 }

 public Users getUser() {
  return user;
 }

 public void setUser(Users user) {
  this.user = user;
 }

 public String getRole() {
  return role;
 }

 public void setRole(String role) {
  this.role = role;
 }

}



Data Layer for Spring Security and Hibernate Configuration

\src\main\java\com\beingjavaguys\dao\login\LoginDao.java
package com.beingjavaguys.dao.login;

import com.beingjavaguys.models.login.Users;



public interface LoginDao {
 Users findByUserName(String username);
}

\src\main\java\com\beingjavaguys\dao\login\LoginDaoImpl.java
package com.beingjavaguys.dao.login;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.beingjavaguys.models.login.Users;

@Repository("loginDao")
public class LoginDaoImpl implements LoginDao{
 
 @Autowired
 SessionFactory sessionFactory;

 Session session = null;
 Transaction tx = null;

 @Override
 public Users findByUserName(String username) {
  session = sessionFactory.openSession();
  tx = session.getTransaction();
  session.beginTransaction();
  Users user = (Users) session.load(Users.class, new String(username));
  tx.commit();
  return user;
 }

}



\src\main\java\com\beingjavaguys\service\login\LoginServiceImpl.java
package com.beingjavaguys.service.login;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import com.beingjavaguys.dao.login.LoginDao;
import com.beingjavaguys.models.login.UserRole;
import com.beingjavaguys.models.login.Users;

@Service("loginService")
public class LoginServiceImpl implements UserDetailsService {

 @Autowired
 LoginDao loginDao;

 @Override
 public UserDetails loadUserByUsername(String username)
   throws UsernameNotFoundException {

  Users user = loginDao.findByUserName(username);

  List authorities = buildUserAuthority(user
    .getUserRole());

  return buildUserForAuthentication(user, authorities);
 }

 private User buildUserForAuthentication(Users user,
   List authorities) {
  return new User(user.getUsername(), user.getPassword(),
    user.isEnabled(), true, true, true, authorities);
 }

 private List buildUserAuthority(Set userRoles) {

  Set setAuths = new HashSet();

  // Build user's authorities
  for (UserRole userRole : userRoles) {
   setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
  }

  List Result = new ArrayList(
    setAuths);

  return Result;
 }

}



Front End Layer files

Login Form \src\main\webapp\WEB-INF\pages\login.jsp
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>Login | Beingjavaguys.com</title>
</head>
<body>
 <center>
  <br /> <br /> <br />
  <div style="border: 1px solid black; width: 300px; padding-top: 10px;">
   <br /> Please enter your username and password to login ! <br /> <span
    style="color: red">${message}</span> <br />
   <form:form method="post" action="j_spring_security_check"
    modelAttribute="users">
    <table>
     <tr>
      <td>Username:</td>
      <td><form:input path="username" /></td>
     </tr>
     <tr>
      <td>Password:</td>
      <td><form:input path="password" /></td>
     </tr>
     <tr>
      <td> </td>
      <td><input type="submit" /></td>
     </tr>
    </table>
   </form:form>
  </div>
 </center>

</body>
</html>


\src\main\webapp\WEB-INF\pages\home.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>Home Page | Beingjavaguys.com</title>
</head>
<body>
 <center>
  <br /> <br /> <br />
  <h1>Default Logged in User page !!!</h1>
  <c:url var="logoutUrl" value="j_spring_security_logout" />
  <form action="${logoutUrl}" method="post">
   <input type="submit" value="Log out" /> <input type="hidden"
    name="${_csrf.parameterName}" value="${_csrf.token}" />
  </form>
 </center>

</body>
</html>


\src\main\webapp\WEB-INF\pages\admin.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>Admin Profile Page | Beingjavaguys.com</title>
</head>
<body>
 <center>
  <br /> <br /> <br />
  <h1>Admin profile page !!!</h1>
  <c:url var="logoutUrl" value="j_spring_security_logout" />
  <form action="${logoutUrl}" method="post">
   <input type="submit" value="Log out" /> <input type="hidden"
    name="${_csrf.parameterName}" value="${_csrf.token}" />
  </form>
 </center>

</body>
</html>


\src\main\webapp\WEB-INF\pages\user.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>User Profile Page | Beingjavaguys.com</title>
</head>
<body>
 <center>
  <br /> <br /> <br />
  <h1>User profile page !!!</h1>
  <c:url var="logoutUrl" value="j_spring_security_logout" />
  <form action="${logoutUrl}" method="post">
   <input type="submit" value="Log out" /> <input type="hidden"
    name="${_csrf.parameterName}" value="${_csrf.token}" />
  </form>
 </center>

</body>
</html>


\src\main\webapp\WEB-INF\pages\403.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>Access Denied | Beingjavaguys.com</title>
</head>
<body>
 <center>
  <br /> <br /> <br />
  <h1>
   Access Denied for User : <span style="color: red;">${username}</span>
  </h1>
  <c:url var="logoutUrl" value="j_spring_security_logout" />
  <form action="${logoutUrl}" method="post">
   <input type="submit" value="Log out" /> <input type="hidden"
    name="${_csrf.parameterName}" value="${_csrf.token}" />
  </form>
 </center>

</body>
</html>


How to run the application

Once you are donw with adding all required file to the project, simple run the application on server and hit following URL: http://localhost:8080/SP_SC_Hibernate/user

It will redirect you to login page (http://localhost:8080/SP_SC_Hibernate/login)



Enter the user credentials "user"/"user@123", and you will get your requested page after a success login:



Now try to see admin page, hit url http://localhost:8080/SP_SC_Hibernate/admin
Now you will get a access denied error, because "user" is not authorized to see "/admin" pages.



That's all for now in, Spring Security with Hibernate with Maven.

More Details on : Spring Security Authentication and Authorization
Download complete Project : Download Link









Thanks for reading !
Being Java Guys Team

Download "Spring Security with Hibernate Example Project" from "SkyDrive"




5 comments:

  1. A typo at Users.java - 'userrole' != 'UserRole'.

    ReplyDelete
  2. And GrantedAuthority at LoginServiceImpl.java

    ReplyDelete
  3. Man thanks! It worked very good. It's a very simple and objective example.

    ReplyDelete
  4. Why i am getting java.lang.NullPointerException

    at com.cea.userservice.CustomAuthenticationProvider.authenticate

    when i am trying ti implement sam logic..... PLEASE HELP ME.....

    ReplyDelete

Like Us on Facebook


Like Us On Google+



Contact

Email: neel4soft@gmail.com
Skype: neel4soft