How to Use Custom DAO Class in Spring Security for Authentication and Authorization

Posted on the 05 March 2013 by Abhishek Somani @somaniabhi

Objective 1 : Use Custom DAO classes in Spring Security Spring Security provides mechanism by which we can specify database queries in spring security xml file , but sometimes we want to use our own custom dao classes which are already built. Objective 2 : Forward the request to different home pages based on the authorized role First , to use your custom dao class , we have to create a bean which implements org.springframework.security.userdetails.UserDetailsService interface. Override the loadUserByUserName method of this interface. We have to create org.springframework.security.userdetails.User from our custom dao object.
package com.security;

import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.userdetails.User;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.userdetails.UsernameNotFoundException;
import com.dal.interfaces.UserDAO;
import com.exceptions.DAOException;

/**
 * //this class is used by spring controller to authenticate and authorize user
 * modified this class to user our Database and defined user roles
 * 
 * @author abhishek.somani
 * 
 */
public class UserDetailServiceImpl implements UserDetailsService {
 private UserDAO userdao;

 public void setUserdao(UserDAO userdao) {
  this.userdao = userdao;
 }

 // this class is used by spring controller to authenticate and authorize
 // user
 @Override
 public UserDetails loadUserByUsername(String userId)
   throws UsernameNotFoundException {
  com.model.User u;
  try {
   u = userdao.get(userId);
   if (u == null)
    throw new UsernameNotFoundException("user name not found");

  } catch (DAOException e) {
   throw new UsernameNotFoundException("database error ");
  }
  return buildUserFromUserEntity(u);

 }

 private User buildUserFromUserEntity(com.model.User userEntity) {
  // convert model user to spring security user
  String username = userEntity.getUserId();
  String password = userEntity.getPassword();
  boolean enabled = true;
  boolean accountNonExpired = true;
  boolean credentialsNonExpired = true;
  boolean accountNonLocked = true;
  GrantedAuthority[] authorities = new GrantedAuthorityImpl[1];
  authorities[0] = new GrantedAuthorityImpl(userEntity.getRole());

  User springUser = new User(username, password, enabled,
    accountNonExpired, credentialsNonExpired, accountNonLocked,
    authorities);
  return springUser;
 }

}

In Spring-security.xml we have to give reference of this bean in user-service-ref in authentication-provider tag.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:security="http://www.springframework.org/schema/security"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
                         http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                        http://www.springframework.org/schema/security
                         http://www.springframework.org/schema/security/spring-security-2.0.1.xsd
                          http://www.springframework.org/schema/context/spring-context-2.5.xsd">

<!-- this is security configuration file which maps urls according to user roles authorization -->

 <security:http auto-config="true">
 <security:logout logout-success-url="/login" invalidate-session="true" logout-url="/logout"/>
  <security:intercept-url pattern="/login.jsp" filters="none" />
  <security:intercept-url pattern="/login" filters="none" />
  <security:intercept-url pattern="/logout" filters="none" />
  <security:intercept-url pattern="/Test"  access="ROLE_ADMIN" />
  <security:intercept-url pattern="/home" access="ROLE_ADMIN,ROLE_USER"/>
  <security:intercept-url pattern="/user/*" access="ROLE_USER" />
  <security:intercept-url pattern="/admin/*" access="ROLE_ADMIN" />
  <security:intercept-url pattern="/*" filters="none"/>
  <security:form-login login-page="/login"
   default-target-url="/home" authentication-failure-url="/login?error=1"
   always-use-default-target="true"/>
  
   
 </security:http>
 <security:authentication-provider
  user-service-ref="userDetailsService" />

 <bean id='userDetailsService' class='com.security.UserDetailServiceImpl'>
  <property name='userdao' ref='userDao' />
 </bean>

</beans>
Now we want to redirect user after authentication and authorization by user. If a user has User role , it should go to home page of user or if a user has admin role then it should go to home page of admin . For this , create a simple controller .After successfull authorization and authentication request.getUserPrinicipal will have the Prinicipal object containing userName which is set in UserDetailServiceImpl and we can check the roles by request.isUserInRole method.In spring-security.xml , set target url to this controller and set always-use-default-target attribute to true in form-login tag , because we always want this controller to execute after user successfully authenticate the user. Sometimes if the request contains referer header , spring security redirect it to that previous link.That is why we set always-use-default-target attribute to true.
package com.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
import com.constants.Constants;
import com.model.UserRoles;
import com.util.CustomLogger;

/**
 * home controller redirects the user based on the roles 
 * @author abhishek.somani
 *
 */
public class HomeController extends AbstractController
{

 @Override
 protected ModelAndView handleRequestInternal(HttpServletRequest request,HttpServletResponse arg1) throws Exception
 {
  //this is the home controller to redirect user to their home pages based on role name 
  // for Admin it should be /admin/home
  //for user it should be /user/home
    
  if (request.isUserInRole("ROLE_USER"))
  {
   request.setAttribute("appendURL", "user");
   return new ModelAndView("user/home", "welcome ", null);
  }
  if (request.isUserInRole("ROLE_ADMIN"))
  {
   request.setAttribute("appendURL", "admin");
   return new ModelAndView("admin/home", "welcome ", null);
  }
  
  throw new Exception("No roles Detected");
 }

}
Do Comment if you face any difficulty.