Spring Security 4 Hibernate Integration Annotation+XML Example

This tutorial demonstrates integrating Hibernate with Spring Security 4 to perform database authentication, showing Annotation+XML configuration example in Spring 4 MVC application.

In this post we will learn Spring Security database authentication using Hibernate annotation+xml based approach. Previous posts discussed about Spring Security in-memory authentication. But in real-world projects, credentials are often stored in database or LDAP. In this post we will go through a complete example of setting up Spring security and verifying credentials directly against database using Hibernate.


What changes compare to in-memory authentication discussed in previous posts?

Only major change is the authentication method itself.

If you recall from previous post, below shown is the setup for in-memory authentication

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

	@Autowired
	public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().withUser("bill").password("abc123").roles("USER");
		auth.inMemoryAuthentication().withUser("admin").password("root123").roles("ADMIN");
		auth.inMemoryAuthentication().withUser("dba").password("root123").roles("ADMIN","DBA");
	}
...
...

This will be changed to following to support database authentication:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

	@Autowired
	@Qualifier("customUserDetailsService")
	UserDetailsService userDetailsService;
	
	@Autowired
	public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService);
	}

All the credentials are now stored in database, and will be accessible to Spring Security via org.springframework.security.core.userdetails.UserDetailsService implementations. We will provide an implementation of UserDetailsService which will eventually use our fully transactional user defined userService to access data from database.

That’s it. Rest of the setup for this post is (deja vu) usual Spring Security, Spring MVC and trivial Hibernate Setup which we have seen many times in previous tutorials.

Below is the full example code for this post. We have divided the responsibilities into separate layers(service/dao) to make it manageable.


Following technologies being used:

  • Spring 4.1.6.RELEASE
  • Spring Security 4.0.1.RELEASE
  • Hibernate 4.3.6.Final
  • MySQL Server 5.6
  • Maven 3
  • JDK 1.7
  • Tomcat 8.0.21
  • Eclipse JUNO Service Release 2

Let’s begin.

Step 1: Project directory structure

Following will be the final project structure:

SpringSecurityHibernateAnnoationExample_img00


SpringSecurityHibernateAnnoationExample_img01

Let’s now add the content mentioned in above structure explaining each in detail.

Step 2: Update pom.xml to include required dependencies

<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>com.websystique.springsecurity</groupId>
  <artifactId>SpringSecurityHibernateAnnotationExample</artifactId>
  <version>1.0.0</version>
  <packaging>war</packaging>

  <name>SpringSecurityHibernateAnnotationExample</name>
  
  	<properties>
		<springframework.version>4.1.6.RELEASE</springframework.version>
		<springsecurity.version>4.0.1.RELEASE</springsecurity.version>
		<hibernate.version>4.3.6.Final</hibernate.version>
		<mysql.connector.version>5.1.31</mysql.connector.version>
	</properties>

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

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

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

		<!-- MySQL -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.connector.version}</version>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.1.0</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>javax.servlet.jsp-api</artifactId>
			<version>2.3.1</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
	</dependencies>

	<build>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<version>3.2</version>
					<configuration>
						<source>1.7</source>
						<target>1.7</target>
					</configuration>
				</plugin>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-war-plugin</artifactId>
					<version>2.4</version>
					<configuration>
						<warSourceDirectory>src/main/webapp</warSourceDirectory>
						<warName>SpringSecurityHibernateAnnotationExample</warName>
						<failOnMissingWebXml>false</failOnMissingWebXml>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
		<finalName>SpringSecurityHibernateAnnotationExample</finalName>
	</build>
</project>


Security Part


Step 3: Add Spring Security Configuration Class

The first and foremost step to add spring security in our application is to create Spring Security Java Configuration. This configuration creates a Servlet Filter known as the springSecurityFilterChain which is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, etc) within our application.

package com.websystique.springsecurity.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

	@Autowired
	@Qualifier("customUserDetailsService")
	UserDetailsService userDetailsService;
	
	@Autowired
	public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService);
	}
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
	  http.authorizeRequests()
	  	.antMatchers("/", "/home").permitAll()
	  	.antMatchers("/admin/**").access("hasRole('ADMIN')")
	  	.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
	  	.and().formLogin().loginPage("/login")
	  	.usernameParameter("ssoId").passwordParameter("password")
	  	.and().csrf()
	  	.and().exceptionHandling().accessDeniedPage("/Access_Denied");
	}
}

As mentioned before, only change is that instead of in-memory authentication, we are using UserDetailService implementations for database-authentication.

Above security configuration in XML configuration format would be:

<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-4.1.xsd
    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd">
     
    <http auto-config="true" >
        <intercept-url pattern="/" access="permitAll" />
        <intercept-url pattern="/home" access="permitAll" />
        <intercept-url pattern="/admin**" access="hasRole('ADMIN')" />
        <intercept-url pattern="/dba**" access="hasRole('ADMIN') and hasRole('DBA')" />
        <form-login  login-page="/login" 
                     username-parameter="ssoId" 
                     password-parameter="password" 
                     authentication-failure-url="/Access_Denied" />
        <csrf/>
    </http>
 
    <authentication-manager >
        <authentication-provider user-service-ref="customUserDetailsService"/>
    </authentication-manager>
     
    <beans:bean id="customUserDetailsService" class="com.websystique.springsecurity.service.CustomUserDetailsService" />
    
</beans:beans>

Step 4: Register the springSecurityFilter with war

Below specified initializer class registers the springSecurityFilter [created in Step 3] with application war.

package com.websystique.springsecurity.configuration;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

}

Above setup in XML configuration format would be:

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

Step 5: Define UserDetailsService implementation

This service is responsible for providing authentication details to Authentication Manager. It implements Spring’s UserDetailsService interface, which contains only one method loadUserByUsername, taking username[ssoId in our example] and returns a org.springframework.security.core.userdetails.User object. We will populate this object using our own UserService which gets data from db using UserDao object.

package com.websystique.springsecurity.service;

import java.util.ArrayList;
import java.util.List;

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.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.websystique.springsecurity.model.User;
import com.websystique.springsecurity.model.UserProfile;

@Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService{

	@Autowired
	private UserService userService;
	
	@Transactional(readOnly=true)
	public UserDetails loadUserByUsername(String ssoId)
			throws UsernameNotFoundException {
		User user = userService.findBySso(ssoId);
		System.out.println("User : "+user);
		if(user==null){
			System.out.println("User not found");
			throw new UsernameNotFoundException("Username not found");
		}
			return new org.springframework.security.core.userdetails.User(user.getSsoId(), user.getPassword(), 
				 user.getState().equals("Active"), true, true, true, getGrantedAuthorities(user));
	}

	
	private List<GrantedAuthority> getGrantedAuthorities(User user){
		List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
		
		for(UserProfile userProfile : user.getUserProfiles()){
			System.out.println("UserProfile : "+userProfile);
			authorities.add(new SimpleGrantedAuthority("ROLE_"+userProfile.getType()));
		}
		System.out.print("authorities :"+authorities);
		return authorities;
	}
	
}


SpringMVC Part


Step 6: Add Controller

package com.websystique.springsecurity.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
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 HelloWorldController {

	
	@RequestMapping(value = { "/", "/home" }, method = RequestMethod.GET)
	public String homePage(ModelMap model) {
		model.addAttribute("greeting", "Hi, Welcome to mysite");
		return "welcome";
	}

	@RequestMapping(value = "/admin", method = RequestMethod.GET)
	public String adminPage(ModelMap model) {
		model.addAttribute("user", getPrincipal());
		return "admin";
	}

	@RequestMapping(value = "/db", method = RequestMethod.GET)
	public String dbaPage(ModelMap model) {
		model.addAttribute("user", getPrincipal());
		return "dba";
	}

	@RequestMapping(value = "/Access_Denied", method = RequestMethod.GET)
	public String accessDeniedPage(ModelMap model) {
		model.addAttribute("user", getPrincipal());
		return "accessDenied";
	}

	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public String loginPage() {
		return "login";
	}

	@RequestMapping(value="/logout", method = RequestMethod.GET)
	public String logoutPage (HttpServletRequest request, HttpServletResponse response) {
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		if (auth != null){    
			new SecurityContextLogoutHandler().logout(request, response, auth);
		}
		return "redirect:/login?logout";
	}

	private String getPrincipal(){
		String userName = null;
		Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

		if (principal instanceof UserDetails) {
			userName = ((UserDetails)principal).getUsername();
		} else {
			userName = principal.toString();
		}
		return userName;
	}


}

Step 7: Add SpringMVC Configuration Class

package com.websystique.springsecurity.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.websystique.springsecurity")
public class HelloWorldConfiguration extends WebMvcConfigurerAdapter {
	
	@Bean(name="HelloWorld")
	public ViewResolver viewResolver() {
		InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
		viewResolver.setViewClass(JstlView.class);
		viewResolver.setPrefix("/WEB-INF/views/");
		viewResolver.setSuffix(".jsp");

		return viewResolver;
	}

	/*
     * Configure ResourceHandlers to serve static resources like CSS/ Javascript etc...
     *
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("/static/");
    }
}

Step 8: Add Initializer class

package com.websystique.springsecurity.configuration;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class[] { HelloWorldConfiguration.class };
	}
 
	@Override
	protected Class<?>[] getServletConfigClasses() {
		return null;
	}
 
	@Override
	protected String[] getServletMappings() {
		return new String[] { "/" };
	}

}


DAO, Model & Service Part


Step 9: Create Model classes

A User can have multiple roles [DBA,ADMIN,USER]. And a Role can be assigned to more than one user. Hence there is a Many-To-Many relationship between a User and UserProfile[role]. We kept this relationship uni-directional [User to UserProfile] as we are only interested in finding Roles for a give user (and not vice-versa). We will be using Many-To-Many association using Join table.

package com.websystique.springsecurity.model;

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

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.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name="APP_USER")
public class User {

	@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
	private int id;

	@Column(name="SSO_ID", unique=true, nullable=false)
	private String ssoId;
	
	@Column(name="PASSWORD", nullable=false)
	private String password;
		
	@Column(name="FIRST_NAME", nullable=false)
	private String firstName;

	@Column(name="LAST_NAME", nullable=false)
	private String lastName;

	@Column(name="EMAIL", nullable=false)
	private String email;

	@Column(name="STATE", nullable=false)
	private String state=State.ACTIVE.getState();

	@ManyToMany(fetch = FetchType.EAGER)
	@JoinTable(name = "APP_USER_USER_PROFILE", 
             joinColumns = { @JoinColumn(name = "USER_ID") }, 
             inverseJoinColumns = { @JoinColumn(name = "USER_PROFILE_ID") })
	private Set<UserProfile> userProfiles = new HashSet<UserProfile>();

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getSsoId() {
		return ssoId;
	}

	public void setSsoId(String ssoId) {
		this.ssoId = ssoId;
	}

	public String getPassword() {
		return password;
	}

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

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getState() {
		return state;
	}

	public void setState(String state) {
		this.state = state;
	}

	public Set<UserProfile> getUserProfiles() {
		return userProfiles;
	}

	public void setUserProfiles(Set<UserProfile> userProfiles) {
		this.userProfiles = userProfiles;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		result = prime * result + ((ssoId == null) ? 0 : ssoId.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof User))
			return false;
		User other = (User) obj;
		if (id != other.id)
			return false;
		if (ssoId == null) {
			if (other.ssoId != null)
				return false;
		} else if (!ssoId.equals(other.ssoId))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", ssoId=" + ssoId + ", password=" + password
				+ ", firstName=" + firstName + ", lastName=" + lastName
				+ ", email=" + email + ", state=" + state + ", userProfiles=" + userProfiles +"]";
	}

	
}

package com.websystique.springsecurity.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="USER_PROFILE")
public class UserProfile {

	@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
	private int id;	

	@Column(name="TYPE", length=15, unique=true, nullable=false)
	private String type = UserProfileType.USER.getUserProfileType();
	
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}


	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		result = prime * result + ((type == null) ? 0 : type.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof UserProfile))
			return false;
		UserProfile other = (UserProfile) obj;
		if (id != other.id)
			return false;
		if (type == null) {
			if (other.type != null)
				return false;
		} else if (!type.equals(other.type))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "UserProfile [id=" + id + ",  type=" + type	+ "]";
	}
	

}
package com.websystique.springsecurity.model;

public enum UserProfileType {
	USER("USER"),
	DBA("DBA"),
	ADMIN("ADMIN");
	
	String userProfileType;
	
	private UserProfileType(String userProfileType){
		this.userProfileType = userProfileType;
	}
	
	public String getUserProfileType(){
		return userProfileType;
	}
	
}
package com.websystique.springsecurity.model;

public enum State {

	ACTIVE("Active"),
	INACTIVE("Inactive"),
	DELETED("Deleted"),
	LOCKED("Locked");
	
	private String state;
	
	private State(final String state){
		this.state = state;
	}
	
	public String getState(){
		return this.state;
	}

	@Override
	public String toString(){
		return this.state;
	}

	public String getName(){
		return this.name();
	}


}

Step 10: Create Dao Layer

package com.websystique.springsecurity.dao;

import java.io.Serializable;

import java.lang.reflect.ParameterizedType;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

public abstract class AbstractDao<PK extends Serializable, T> {
	
	private final Class<T> persistentClass;
	
	@SuppressWarnings("unchecked")
	public AbstractDao(){
		this.persistentClass =(Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
	}
	
	@Autowired
	private SessionFactory sessionFactory;

	protected Session getSession(){
		return sessionFactory.getCurrentSession();
	}

	@SuppressWarnings("unchecked")
	public T getByKey(PK key) {
		return (T) getSession().get(persistentClass, key);
	}

	public void persist(T entity) {
		getSession().persist(entity);
	}

	public void delete(T entity) {
		getSession().delete(entity);
	}
	
	protected Criteria createEntityCriteria(){
		return getSession().createCriteria(persistentClass);
	}

}
package com.websystique.springsecurity.dao;

import com.websystique.springsecurity.model.User;

public interface UserDao {

	User findById(int id);
	
	User findBySSO(String sso);
	
}
package com.websystique.springsecurity.dao;

import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

import com.websystique.springsecurity.model.User;

@Repository("userDao")
public class UserDaoImpl extends AbstractDao<Integer, User> implements UserDao {

	public User findById(int id) {
		return getByKey(id);
	}

	public User findBySSO(String sso) {
		Criteria crit = createEntityCriteria();
		crit.add(Restrictions.eq("ssoId", sso));
		return (User) crit.uniqueResult();
	}

	
}

Step 11: Create Service Layer

package com.websystique.springsecurity.service;

import com.websystique.springsecurity.model.User;

public interface UserService {

	User findById(int id);
	
	User findBySso(String sso);
	
}
package com.websystique.springsecurity.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.websystique.springsecurity.dao.UserDao;
import com.websystique.springsecurity.model.User;

@Service("userService")
@Transactional
public class UserServiceImpl implements UserService{

	@Autowired
	private UserDao dao;

	public User findById(int id) {
		return dao.findById(id);
	}

	public User findBySso(String sso) {
		return dao.findBySSO(sso);
	}

}


Hibernate Configuration Part


Step 12: Create Hibernate Configuration

Hibernate configuration class contains @Bean methods for DataSource, SessionFactory & Transaction Manager. Datasource properties are taken from
application.properties file and contains connection details for MySQL database.

package com.websystique.springsecurity.configuration;

import java.util.Properties;

import javax.sql.DataSource;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@ComponentScan({ "com.websystique.springsecurity.configuration" })
@PropertySource(value = { "classpath:application.properties" })
public class HibernateConfiguration {

    @Autowired
    private Environment environment;

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[] { "com.websystique.springsecurity.model" });
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
     }
	
    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
        dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
        dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
        dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
        return dataSource;
    }
    
    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
        return properties;        
    }
    
    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory s) {
       HibernateTransactionManager txManager = new HibernateTransactionManager();
       txManager.setSessionFactory(s);
       return txManager;
    }
}

application.properties

jdbc.driverClassName = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/websystique
jdbc.username = myuser
jdbc.password = mypassword
hibernate.dialect = org.hibernate.dialect.MySQLDialect
hibernate.show_sql = true
hibernate.format_sql = true


Views Part


Step 13: Add Views

login.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
		<title>Login page</title>
		<link href="<c:url value='/static/css/bootstrap.css' />"  rel="stylesheet"></link>
		<link href="<c:url value='/static/css/app.css' />" rel="stylesheet"></link>
		<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.css" />
	</head>

	<body>
		<div id="mainWrapper">
			<div class="login-container">
				<div class="login-card">
					<div class="login-form">
						<c:url var="loginUrl" value="/login" />
						<form action="${loginUrl}" method="post" class="form-horizontal">
							<c:if test="${param.error != null}">
								<div class="alert alert-danger">
									<p>Invalid username and password.</p>
								</div>
							</c:if>
							<c:if test="${param.logout != null}">
								<div class="alert alert-success">
									<p>You have been logged out successfully.</p>
								</div>
							</c:if>
							<div class="input-group input-sm">
								<label class="input-group-addon" for="username"><i class="fa fa-user"></i></label>
								<input type="text" class="form-control" id="username" name="ssoId" placeholder="Enter Username" required>
							</div>
							<div class="input-group input-sm">
								<label class="input-group-addon" for="password"><i class="fa fa-lock"></i></label> 
								<input type="password" class="form-control" id="password" name="password" placeholder="Enter Password" required>
							</div>
							<input type="hidden" name="${_csrf.parameterName}"  value="${_csrf.token}" />
								
							<div class="form-actions">
								<input type="submit"
									class="btn btn-block btn-primary btn-default" value="Log in">
							</div>
						</form>
					</div>
				</div>
			</div>
		</div>

	</body>
</html>

As you can see, the CSRF parameters are accessed using EL expressions in your JSP, you may additionally prefer to force EL expressions to be evaluated, by adding following to the top of your JSP:

<%@ page isELIgnored="false"%>

welcome.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"  pageEncoding="ISO-8859-1"%>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
	<title>Welcome page</title>
</head>
<body>
	Greeting : ${greeting}
	This is a welcome page.
</body>
</html>

admin.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
	<title>Admin page</title>
</head>
<body>
	Dear <strong>${user}</strong>, Welcome to Admin Page.
	<a href="<c:url value="/logout" />">Logout</a>
</body>
</html>

dba.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
	<title>DBA page</title>
</head>
<body>
	Dear <strong>${user}</strong>, Welcome to DBA Page.
	<a href="<c:url value="/logout" />">Logout</a>
</body>
</html>

accessDenied.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
	<title>AccessDenied page</title>
</head>
<body>
	Dear <strong>${user}</strong>, You are not authorized to access this page
	<a href="<c:url value="/logout" />">Logout</a>
</body>
</html>


Database Schema Part


Step 14: Create Database Schema & Populate dummy data

As already explained in Step 9, there is a Many-To-Many relationship between User and UserProfile. Many-To-Many relationship is maintained using Join table, and it is unidirectional(from User to UserProfile) as the other case (finding all users with Admin role e.g. does not make much sense in this example)


/*All User's are stored in APP_USER table*/
create table APP_USER (
   id BIGINT NOT NULL AUTO_INCREMENT,
   sso_id VARCHAR(30) NOT NULL,
   password VARCHAR(100) NOT NULL,
   first_name VARCHAR(30) NOT NULL,
   last_name  VARCHAR(30) NOT NULL,
   email VARCHAR(30) NOT NULL,
   state VARCHAR(30) NOT NULL, 	
   PRIMARY KEY (id),
   UNIQUE (sso_id)
);
 
/* USER_PROFILE table contains all possible roles */
create table USER_PROFILE(
   id BIGINT NOT NULL AUTO_INCREMENT,
   type VARCHAR(30) NOT NULL,
   PRIMARY KEY (id),
   UNIQUE (type)
);
 
/* JOIN TABLE for MANY-TO-MANY relationship*/ 
CREATE TABLE APP_USER_USER_PROFILE (
    user_id BIGINT NOT NULL,
    user_profile_id BIGINT NOT NULL,
    PRIMARY KEY (user_id, user_profile_id),
    CONSTRAINT FK_APP_USER FOREIGN KEY (user_id) REFERENCES APP_USER (id),
    CONSTRAINT FK_USER_PROFILE FOREIGN KEY (user_profile_id) REFERENCES USER_PROFILE (id)
);

/* Populate USER_PROFILE Table */
INSERT INTO USER_PROFILE(type)
VALUES ('USER');

INSERT INTO USER_PROFILE(type)
VALUES ('ADMIN');

INSERT INTO USER_PROFILE(type)
VALUES ('DBA');

/* Populate APP_USER Table */
INSERT INTO APP_USER(sso_id, password, first_name, last_name, email, state)
VALUES ('bill','abc123', 'Bill','Watcher','bill@xyz.com', 'Active');

INSERT INTO APP_USER(sso_id, password, first_name, last_name, email, state)
VALUES ('danny','abc124', 'Danny','Theys','danny@xyz.com', 'Active');

INSERT INTO APP_USER(sso_id, password, first_name, last_name, email, state)
VALUES ('sam','abc125', 'Sam','Smith','samy@xyz.com', 'Active');

INSERT INTO APP_USER(sso_id, password, first_name, last_name, email, state)
VALUES ('nicole','abc126', 'Nicole','warner','nicloe@xyz.com', 'Active');

INSERT INTO APP_USER(sso_id, password, first_name, last_name, email, state)
VALUES ('kenny','abc127', 'Kenny','Roger','kenny@xyz.com', 'Active');

/* Populate JOIN Table */
INSERT INTO APP_USER_USER_PROFILE (user_id, user_profile_id)
  SELECT user.id, profile.id FROM app_user user, user_profile profile  
  where user.sso_id='bill' and profile.type='USER';

INSERT INTO APP_USER_USER_PROFILE (user_id, user_profile_id)
  SELECT user.id, profile.id FROM app_user user, user_profile profile
  where user.sso_id='danny' and profile.type='USER';

INSERT INTO APP_USER_USER_PROFILE (user_id, user_profile_id)
  SELECT user.id, profile.id FROM app_user user, user_profile profile
  where user.sso_id='sam' and profile.type='ADMIN';

INSERT INTO APP_USER_USER_PROFILE (user_id, user_profile_id)
  SELECT user.id, profile.id FROM app_user user, user_profile profile
  where user.sso_id='nicole' and profile.type='DBA';

INSERT INTO APP_USER_USER_PROFILE (user_id, user_profile_id)
  SELECT user.id, profile.id FROM app_user user, user_profile profile  
  where user.sso_id='kenny' and profile.type='ADMIN';

INSERT INTO APP_USER_USER_PROFILE (user_id, user_profile_id)
  SELECT user.id, profile.id FROM app_user user, user_profile profile  
  where user.sso_id='kenny' and profile.type='DBA';

We have created tables for User, UserProfile and Join table(to manage Many-To-Many relation ship). We populated following users and roles:

Bill,Danny : USER
Sam        : ADMIN
Nicole     : DBA
Kenny      : ADMIN, DBA

Below are the snapshots of MySQL database at this moment.

SpringSecurityHibernateAnnoationExample_img2
SpringSecurityHibernateAnnoationExample_img3
SpringSecurityHibernateAnnoationExample_img4

Now we will start our web application and try to login & access different part of applications, using different users.

Step 15: Build and Deploy the application

Now build the war (either by eclipse/m2eclipse) or via maven command line( mvn clean install). Deploy the war to a Servlet 3.0 container . Since here i am using Tomcat, i will simply put this war file into tomcat webapps folder and click on start.bat inside tomcat bin directory.

Run the application
Open browser and goto localhost:8080/SpringSecurityHibernateAnnotationExample/

SpringSecurityHibernateAnnoationExample_img5

Now try to access localhost:8080/SpringSecurityHibernateAnnotationExample/admin, you will be prompted for login

SpringSecurityHibernateAnnoationExample_img6

Provide credentials of a ‘USER’ role.

SpringSecurityHibernateAnnoationExample_img7

Submit, you will see AccessDenied Page

SpringSecurityHibernateAnnoationExample_img8

Now logout and try to access admin page again

SpringSecurityHibernateAnnoationExample_img9

Provide wrong password

SpringSecurityHibernateAnnoationExample_img10

Provide proper admin role credentials and login

SpringSecurityHibernateAnnoationExample_img11

Now try to access db page on localhost:8080/SpringSecurityHibernateAnnoationExample/db, you will get AccessDenied page.

SpringSecurityHibernateAnnoationExample_img12

Now logout, provide a DBA credentials, and access admin page on localhost:8080/SpringSecurityHibernateAnnoationExample/admin
SpringSecurityHibernateAnnoationExample_img13

Logout. Enough for today.

SpringSecurityHibernateAnnoationExample_img14

That’s it. Next post shows how to use role based login in Spring Security 4 using Hibernate setup.

Download Source Code



References

If you like tutorials on this site, why not take a step further and connect me on Facebook , Google Plus & Twitter as well? I would love to hear your thoughts on these articles, it will help me improve further our learning process.

If you appreciate the effort I have put in this learning site, help me improve the visibility of this site towards global audience by sharing and linking this site from within and beyond your network. You & your friends can always link my site from your site on www.websystique.com, and share the learning.

After all, we are here to learn together, aren’t we?

  • Subhadeep Dey

    does spring execute all the methods of a class annotated with @Configuration ??
    when does spring execute the following method ??
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth)

  • Nikita Patel

    when i Enter
    INSERT INTO APP_USER_USER_PROFILE (user_id, user_profile_id) SELECT user.id, profile.id FROM app_user user, user_profile profile where user.sso_id=’bill’ and profile.type=’USER’; in MySQL It give Following Error..
    Error Code: 1146. Table ‘websystique.app_user’ doesn’t exist

    • websystique

      Don’t forget to Create the tables under specific schema [Step-14 in the post].

      • Nikita Patel

        I can change .

        INSERT INTO APP_USER_USER_PROFILE (user_id, user_profile_id)
        SELECT user.id, profile.id FROM app_user user, user_profile profile
        where user.sso_id=’sam’ and profile.type=’ADMIN’;

        To

        INSERT INTO APP_USER_USER_PROFILE (user_id, user_profile_id)
        SELECT user.id, profile.id FROM APP_USER user, USER_PROFILE profile
        where user.sso_id=’sam’ and profile.type=’ADMIN’;

        and It’s Works….

        Thanks Sir…

  • Himanshu

    Hi,

    It is very good article, thanks for sharing knowledge.
    However when I downloaded the app and tried to run it on Eclipse + Tomcat 8, I got 404. please help me to launch the application.

    • websystique

      Hi, Please make sure that you are providing an Implementation ofr UserDetailsService [CustomUserDetailsService in this example] and it is annotated appropriately.

      • Himanshu

        Thanks for response.
        The problem was i did mistake while defining ManyToMany relation on User class in inversejoin gave the same user_id column by mistake, so it was not working.

        Thank You for post

  • Bhargav Patel

    Hi,

    Is it possible to change role and url mapping runtime ?? I mean suppose i have url called addUser and has only access to admin. Now i want to give access to my HR dept. is there and way to to achieve this like change role-url mapping change user-role maping. i am asking you this becuase if we have thousand of url then its quite time consuming and hard to maintain andevery time we will have to restart the server.

    Thanks,
    Bhargav

    • websystique

      You can categorize the additional entities under specific roles and use those defined roles in your security configuration. Normally you don’t change the security configuration on the fly. What you could do is to externalize the configuration in property file[ or database] and use some way [@value annotation] to get the url’s and roles while preparing security configuration you want to configure.

  • Pingback: Spring Security 4 Method security using @PreAuthorize,@PostAuthorize, @Secured, EL - WebSystique()

  • Pingback: Spring MVC 4 + Spring Security 4 + Hibernate Example - WebSystique()

  • Irina

    Dear author, you manual is very useful, but I have one problem with spring security. When we
    change one user of our project to user of spring in line below

    return new org.springframework.security.core.userdetails.User(user.getSsoId(), user.getPassword(),
    user.getState().equals(“Active”), true, true, true, getGrantedAuthorities(user))

    I get UserNotFoundException from method
    user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
    in class AbstractUserDetailsAuthenticationProvider.

    Could you help me please?

    • websystique

      Hi Irina, I would need more information in order to find the issue. Could you please share the code for retrieveUser?

      • Irina

        When I try to choose this method for more information I get

        protected abstract UserDetails retrieveUser(String username,
        UsernamePasswordAuthenticationToken authentication)
        throws AuthenticationException;

        That why I can’t understand the reason of exception.

  • sandeep pandey

    In this example we are only validating existence of user & role by loadbyUserName(String ssio), But how do we compare password? I mean which class to use to get methods in which spring injects user and pwd as it injects username in loadbyUserName(String username). Any help would be appreciated !! thx

    • sandeep pandey

      I got it, If I understand correctly it is when user is returned with password , it internally matches user entered password with retrieved pwd from repository .

      • websystique

        Right.

  • Pingback: Spring Security 4 Hibernate Role Based Login Example - WebSystique()

  • Sandeep Bhalothia

    Very nice site, thanks for your posts and explanations.

    I have one error in my setup.

    Error code 403, Proxy Unacknowledged -> [Help 1]

    [ERROR]

    [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.

    [ERROR] Re-run Maven using the -X switch to enable full debug logging.

    [ERROR]

    [ERROR] For more information about the errors and possible solutions, please read the following articles:

    [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/DependencyResolutionException

    I hope this is due to setting.xml file.

    Can you please send/attach setting.xml file as well.

    Thanks,

    Sandeep

    • Sandeep Bhalothia

      I am having some issues with the proxy settings, so is it possible to share the .m2 folder so we can use that directly?

      Thanks
      Sandeep

      • websystique

        Hi Sandeep,

        You just have to uncomment the proxy config in your settings.xml [usually found in $M2_HOME/conf folder], and update with your proxy username/password/host/port:

        optional
        true
        http
        proxyuser
        proxypass
        proxy.host.net
        8080
        local.net|some.host.com

  • Pingback: Spring Security 4 Role Based Login Example - WebSystique()

  • Sachin Raghav

    Hi, Can we execute it directly from eclipse? when i had tried to run this application,there is no option to select ‘run on server’. Can you please tell me ?

    • websystique

      Hi Sachin,

      Probably because there is no server configured yet. Please have a look at Setup Tomcat in Eclipse.

      • Sachin Raghav

        Hi, i have server . i have just download and import the project in eclipse. but when i click on run it shows only run as Java Application .see the attached images . i could not understand why this happens?

        • websystique

          You have some error in your project.Did you try to do a Maven update for your project. Additionally, did you update Deployment Assembly as mentioned in the link i shared? I would suggest you to go through the steps in that link, it’s tried & tested way + easy to follow. You may also want to add following in the plugins section of this project, to avoid the annoying eclipse java-version switch on Maven update.

          org.apache.maven.plugins
          maven-compiler-plugin
          3.2

          1.7
          1.7

          Let me know the outcome.

        • biswajit bastia

          Go to your project properties and and click in project facets check if its dynamic web project or not.if not mark it as dynamic web project then it will show run on server option .

  • Santoshi Mystique

    Hey Your tutorial is very nice I downloaded this application and I changed the “ssoId” in data base to “user_name” right now its working fine but my problem is when I changed the “ssoId” in login Page to “userName” its showing “invalid username and password” according to the message, I checked every where I changed it but why its not working in this case ….Help me please….!

    and where is POST method for login…?

    And one more thing are u using Hibernate tool to generate model class? or any other resources…

    Thanks in adv.

    • websystique

      Hi Santoshi,

      If you have renamed it everywhere[including SecurityConfiguration & CustomUserDetailService], there is no reason it should not work. If you still have the issue, could you please create a github project and drop me a link. I’ll have a look. For your other question : the error message you see is generic [used in login jsp] , shown when login is not successful. I always code the models by myself, no tool being used.

      • Santoshi Mystique

        Thanks dear thanks for the reply. I made it. I forgot to change security configuration and right now its okay.

      • Santoshi Mystique

        And one more thing dear why I am getting the error in this line in every jsp…I checked in maven dependency the related jar files are there for JSTL and Spring as well… but still why…Thanks again.

        • Santoshi Mystique

          help me out please….

          • websystique

            Hi Santoshi, as i understood from your questions, you are sure having those jstl and spring tlds in your your application, & your application itself runs fine, but just in eclipse, you see those red-marks witinin your JSP’s. Then It has to be Eclipse ideosynchrasy. Have a look at this StackOverflow post, might be the solution for your issue.

          • Santoshi Mystique

            thanks dude Its fine now

  • SomeoneYouDontWannaArgueWith

    This was easy to follow. Thank you. Got it working. Well documented

  • Stephen Battey

    Great tutorial. This has really helped me get started with the security layer in Spring.

    I spotted an important typo in the XML configuration.
    The paths to “admin” and “dba” don’t have a forward slash (which they do in the configuration-in-code version).

    This was subtle because the value “/admin**”:
    - does protect calls to “/admin”
    - but doesn’t protect calls to “/admin/users”

    So I think the intercept-url config should be:

    • websystique

      Thanks Stephan.

  • Yogesh Chavan

    Hi, thanks for this tutorial , but i am confused as how the password is getting verified here ? because the query we do from the database is just using the username/ssoid .. please help to understand ..thanks

  • Ivan Ato Paitoo

    I have been trying to run this project all day and i still can not get it to run it throws this Exception [alter table USER_ROLES add constraint FKcwwvhxt7bgydljuqkbiach53m foreign key (USER_ID) references users (id)
    i have deleted and crated tables and even database but the same Exception what is missing

    • websystique

      Hi Ivan,
      There is no USER_ROLES table in this example by the way. Probably this is your joined table [as APP_USER_USER_PROFILE in this post]. You seem to get this error because you are trying to insert/delete/update something in this joined table which does not maintain a reference to a row in APP_USER table. Also note that , both column in this joined table are NON-NULL, referring to APP_USER & USER_PROFILE table, so make sure every row in there refers to a row in APP_USER & USER_PROFILE.

  • anrede

    Hi! I just downloaded and ran the project. can you guys help me out? How can I fix this problem?

    • websystique

      Hi Anrede, sorry i missed your message.Which issue are you getting?This is not evident in your screenshot.

  • Imad Eddin

    Hi, This is the best tutorial on the internet.
    Thank you for your effort, and I wish you success in every aspect of your life as much as the success in this perfect tutorial.

    Thank you

    • websystique

      Glad you liked it Imad. Thanks a lot.

  • amabb

    Hi !

    thx for the tutorial, very helpful !

    I’m getting this lines in tomcat log :
    —————————
    User : null
    User not found
    —————————
    from loadUserByUsername() method when i try to log in.

    Everything’s ok.. But I cannot get the user from the db using the DAO.. it returns null value.
    anyone of you got this error before?

    • websystique

      Hi,
      In CustomUserDetailsService , we are using userService to get the user from database based on unique key SSO_ID. It means in your case you don’t have a user in your database with the SSO_ID you are trying to fetch with. Could you please check?

      • amabb

        thx for the quick answer.
        Yes I have users in my db, i tried kenny/abc127 and bill/abc123.. No one works

        • websystique

          Hi,
          I can’t think about a known cause for this issue based on your comment that your users are in database. I wonder if your deployment on tomcat itself was OK? Or in other words, were you able to even connect to database on first place?

          • Amayas ABBOUTE

            Hi,

            I tried to connect to the db from the controller like this :

            @Autowired
            UserService userService;

            @RequestMapping(value ={“/”, “/home”}, method = RequestMethod.GET)
            public String homePage(ModelMap model) {

            User user = userService.findBySso(“kenny”);

            model.addAttribute(“greeting”, “Hi, Welcome to my site” + user.getFirstName() + ” ” + user.getLastName());

            return “welcome”;
            }

            and it returns a null pointer exception :/

            In the UserServiceImpl class, it returns null value… it seems that the sql query to get the user doesn’t work, i don’t see the query in the logs..

            Any idea ? I checked every thing, I tried the same code without the security layer and I was able to retrive the user from the db..

          • amabb

            Hi,

            I tried to connect to the db from the controller like this :

            @Autowired

            UserService userService;

            @RequestMapping(value ={“/”, “/home”}, method = RequestMethod.GET)

            public String homePage(ModelMap model) {

            User user = userService.findBySso(“kenny”);

            model.addAttribute(“greeting”, “Hi, Welcome to my site” + user.getFirstName() + ” ” + user.getLastName());

            return “welcome”;

            }

            and it returns a null pointer exception :/

            In the UserServiceImpl class, it returns null value… it seems that the sql query to get the user doesn’t work, i don’t see the query in the logs..

            Any idea ? I checked every thing, I tried the same code without the security layer and I was able to retrive the user from the db..

          • websystique

            Hi,
            It seems your DB configuration is not right. The database you are actually connected to does not contain any data. Could you please double check the database configuration [HibernateConfiguration & application.properties]? There is no other reason userService(& eventually userDao) would return null value if the database had the values populated.

          • amabb

            It works know ! I reviewed the various configuration classes and the database properties. I did not change lot of things..

            Thank you ! :)

  • Marcin Marcin

    Hello,

    I have question, how I can get all records from database for table users? With “persist” method?

    Thanks,

    • websystique

      Hi Marcin, Look at this post, here we are using a simple cretiria to fetch all users.

  • Pingback: Spring4 javaConfig配置方式并集成JUnit-IT大道()

  • Abhijeet

    hi,

    Restrictions.eq(“ssoId”, sso) from

    UserDaoImpl give case insensitive results…..I am using MySQL database.
    Thanks in advance

  • Sof Ham

    Hi, I would like to thank you for this super tutorial.

    I have an issue caused by the exception :

    Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mintad.springsecurity.dao.UserDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1103)

    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:963)

    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)

    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)

    … 37 more

    • websystique

      Hi Sof,

      Either you are missing @Repository annotation on UserDaoImpl class or your DAO class is not scnaned.Make sure that package your class is in, is covered in @ComponentScan

      @ComponentScan(basePackages = “com.websystique.springsecurity”)
      public class HelloWorldConfiguration extends WebMvcConfigurerAdapter {….}

      • Sof Ham

        You’re right. It was a quick question from my side. UserDao et UserDaoImpl were in a different package.

  • aliye

    Hi ,
    Thanks for this very helpful tutorial. Just one extra question.
    I would like to keep encrypted passwords in database . It means that password input has to be encrypted before passing to CustomUserDetailsService. What is the best way to do it?

  • Rajesh Patel

    Hi!
    When I imported this project in eclipse, there is no ‘Run on Server’ option for this project. I can see the option in other projects but not this one. Please advise.

    • websystique

      Hi Rajesh, Did you try to perform maven-> update project in eclipse after downloading it?

      • Rajesh Patel

        Hey – Thanks for the reply. I was able to fix it by making some changes under “Project Facets” by enabling Dynamic Web project.

  • Alejandro Fng

    Hi! I just downloaded and ran the project. can you guys help me out? I dont get why it is not working. Using tomcat 8, jdk 1.8,

    • websystique

      Hi Alejandro, First you need to fix build-path for your project . project->right-click->properties->java Build Path->Libraries. Here you will provide the java version you have (as you mentioned 1.8). Once done, click ok, and then again project->right-click->Maven->Update project. Here select your project and OK.

      Additionally, it seems to me that your tomcat setup is not proper: Please follow this link to configure it properly.

      You should be good to go.If you still face any issue, let me know.

    • uday kumar

      to solve this issue you have to make a small change in pom.xml . add this plugin :

      maven-compiler-plugin

      1.8

      1.8

      plugins tag in pom.xml should look like

      org.apache.maven.plugins

      maven-war-plugin

      2.4

      src/main/webapp

      SpringSecurityHibernateAnnotationExample

      false

      maven-compiler-plugin

      1.8

      1.8

  • Erwin

    Back with another question if you don’t mind. Right now you have to manually add new users to the app_user_user_profile table and assign them a user_profile (unless I implemented it wrong). Is there an easy way to automatically add new users to that table and give them a default role of ‘user’?

    Kind regards,

    Erwin

    • websystique

      Hi Erwin. This post contains your answer. Let me know you face any issue.

      • Erwin

        Thanks!

  • Francisco Noguera

    Hi I download the code, but I dont see the configuration files (spring-security.xml, servlet-context.xml, etc). I dont know which is the file to add the filters I try in one project I have but doesnt work, or the location for the configuration files that I must create to deploy the project. I appreciate the help. Regards

  • Erwin

    Hiya, I have another question, I hope you don’t mind. Right now you are manually populating the APP_USER_USER_PROFILE table, but I imagine that in a production environment you’d want to automatically create a new entry in that table whenever a new user is created, with perhaps a default user_profile_id of 1. Is there an easy way to achieve that?

    By the way, thanks for these tutorials, they’re a great resource.

  • renam chagas

    Good evening!!

    I keep getting this error:

    Caused by: org.hibernate.TypeMismatchException: Provided id of the wrong type for class com.websystique.springsecurity.model.User. Expected: class java.lang.Integer, got class java.lang.String

    at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:134)

    at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1070)

    at org.hibernate.internal.SessionImpl.access$2000(SessionImpl.java:176)

    at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2551)

    at org.hibernate.internal.SessionImpl.get(SessionImpl.java:955)

    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:1110)

    … 44 more

    • websystique

      Hi Renam,

      Seems that somewhere in your custom code, you are trying to use String type for ‘id’ which is in fact a type of int [Look at User & UserProfile Entities]. Could you please check? If you don’t find anything, i might ask you to provide full exception you are getting.

      • renam chagas

        Thanks for replying!

        i couldn`t find any part of my code that I would be passing a String for the ID.

        Here the full exception:

        GRAVE: An internal error occurred while trying to authenticate the user.

        org.springframework.security.authentication.InternalAuthenticationServiceException: Provided id of the wrong type for class com.websystique.springsecurity.model.User. Expected: class java.lang.Integer, got class java.lang.String

        at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:125)

        at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:143)

        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)

        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)

        at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:93)

        at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)

        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)

        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)

        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)

        at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:120)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)

        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)

        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)

        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)

        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)

        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)

        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)

        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)

        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)

        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)

        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)

        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)

        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)

        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)

        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)

        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)

        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)

        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:957)

        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)

        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)

        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)

        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620)

        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)

        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)

        at java.lang.Thread.run(Thread.java:745)

        • websystique

          Hi Renam,

          Are you using this example as it is from download OR you made some changes in CustomUserDetailsService class?

          Additionally, may i know which versions of Spring/Hibernate/Security you are getting this error with and if the error is reproducible? Would it be possible to share your minimal code somehow, so that i can myself try to reproduce the issue and find the real problem+solution?

  • Erwin

    Hiya,

    What is the reason behind putting the user_profile_id column in a separate table entirely (app_user_user_profile) instead of just making an extra column in the app_user table?

    • websystique

      Hi Erwin,

      This is because i wanted to maintain Many-To-Many relations between USER & USER_PROFILE. One user can have multiple Roles, and one Role can be assigned to multiple users.

      • Erwin

        Ah I understand now, thank you.

        • websystique

          Hi Erwin, On your question related to APP_USER_USER_PROFILE population for new user, i would suggest you to go through hibernate-many-to-many-unidirectional-annotation-example. This post explains in detail saving a tuple with Many-To-Many relationship. Any other question, feel free to ask.

          • Erwin

            Cheers!

  • amit

    nice code

    i try to run

    than

    WARNING: Request method ‘POST’ not supported

    Sep 08, 2015 1:00:03 PM org.springframework.web.servlet.PageNotFound handleHttpRequestMethodNotSupported

    WARNING: Request method ‘POST’ not supported

    Sep 08, 2015 1:00:59 PM org.springframework.web.servlet.PageNotFound handleHttpRequestMethodNotSupported

    WARNING: Request method ‘POST’ not supported

    i think something is missing or i am doing something wrong

    • websystique

      Hi Amit,

      Are you using the same code attached in download of this post? Did you add some new requests handling? If not then, Are you able to reproduce the scenario? It would be helpful to post that scenario where you are getting this error, i will take a look as soon as i got it.

      • amit

        yes i just download and run

        everything going good still creating db as i added hibernate.hbm2ddl.auto = create

        welcome page
        and admin page also redirect to security
        but when enter username and password
        show post not supported
        face same problem in custom login with out db

        • websystique

          Hi Amit,

          I am not able to reproduce the scenario you might be getting. But probably you found a real issue, which could be related to CSRF handling.

          To identify if it is the problem, May i ask you to switch off CSRF and see if you see the problem occurring again. It will help me provide a fix.

          [Sorry I could have done it myself but i am simply not getting this problem.]

          1) Disable CSRF in SecurityConfiguration.java

          replace

          .and().csrf()
          .and().exceptionHandling().accessDeniedPage(“/Access_Denied”);

          By

          .and().exceptionHandling().accessDeniedPage(“/Access_Denied”).and().csrf().disable();

          2) Comment CSRF hidden parameter in login.jsp

          Comment this line

          Please try to do these changes and let me know if you are still facing the problem.

          Thanks.

          • k mohan

            hi changed in login.jsp ,but still i am getting post method not supported

          • k mohan

            it working now ,i add <%@ page isELIgnored="false"% in login.jsp

          • k mohan

            thanks very much u done amazing job

  • Guilherme Marquesini Reis Ribe

    When I do the login writing wrong credentials, like username, the tomcat throw exception because I didn’t have the user. The method ‘loadUserByUsername’ return null to shiro security.
    How can I catch this exception correctly?

    GRAVE: An internal error occurred while trying to authenticate the user.
    org.springframework.security.authentication.InternalAuthenticationServiceException: UserDetailsService returned null, which is an interface contract violation

    • websystique

      Hi Guilherme, thanks for reporting this issue. I missed to throw proper exception [ throw new UsernameNotFoundException("Username not found");] from loadUserByUsername when user is not found. I’ve updated the post and downloadble.

      Thanks again,