Spring Security with JDBC User Details and JSF 2.0

We will add on to our last remember me tutorial.

In this tutorial instead of hard coded username, password we will add JDBC default support provided by Spring.

First we will update jsfspring-sec-bean-config.xml and add datasource property. In this tutorial we will use MySQL.

jsfspring-sec-bean-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:sec="http://www.springframework.org/schema/security"
	xsi:schemaLocation="
	   http://www.springframework.org/schema/beans
	   http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
       http://www.springframework.org/schema/security
	   http://www.springframework.org/schema/security/spring-security-3.1.xsd"
	   >
       
	<beans:bean id="navigator" name="navigator" class="com.mumz.jsfspringsec.beans.Navigator" scope="session">
	</beans:bean>
	
	<beans:bean id="loginBean" name="loginBean" class="com.mumz.jsfspringsec.beans.LoginBean" scope="prototype">
		<beans:property name="authenticationManager" ref="authenticationManager"></beans:property>
		<beans:property name="rememberMeServices" ref="rememberMeServices"></beans:property>
	</beans:bean>
	
	<beans:bean id="rememberMeServices"
		class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
		<beans:property name="key" value="jsfspring-sec" /> 
		<beans:property	name="userDetailsService" ref="userDetailsService" /> 
		<beans:property	name="alwaysRemember" value="true" /> 
		<beans:property	name="tokenValiditySeconds" value="60" /> 
	</beans:bean>
	
	<beans:bean id="rememberMeAuthenticationProvider" 
		class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
  		<beans:property name="key" value="jsfspring-sec"/>
	</beans:bean>
	
	<beans:bean id="rememberMeFilter" 
		class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
  		<beans:property name="rememberMeServices" ref="rememberMeServices"/>
  		<beans:property name="authenticationManager" ref="authenticationManager" />
	</beans:bean>
	
	<beans:bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	 	<beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<beans:property name="url" value="jdbc:mysql://localhost:3306/jsf_spring_sec_default" />
		<beans:property name="username" value="root" />
		<beans:property name="password" value="root" />
   </beans:bean>
</beans:beans>

Second we will update our jsfspring-sec-security-config.xml and add jdbc-user-service as authentication manager.

jsfspring-sec-security-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans 
	xmlns:sec="http://www.springframework.org/schema/security"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:beans="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="
	   http://www.springframework.org/schema/beans
	   http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
	   http://www.springframework.org/schema/security
	   http://www.springframework.org/schema/security/spring-security-3.1.xsd">
	   
	 <sec:http auto-config="true" use-expressions="true">
		<sec:intercept-url pattern="/pages/secure/**" access="hasRole('ROLE_USER')" />
		<sec:intercept-url pattern="/pages/unsecure/**" access="permitAll"/>
		<sec:intercept-url pattern="/pages/common/**" access="permitAll"/>
		<sec:intercept-url pattern="/**" access="permitAll"/>
		<sec:form-login login-page="/pages/common/login.jsf"/>
		<sec:remember-me key="jsfspring-sec" services-ref="rememberMeServices"/>
		<sec:logout 
			invalidate-session="true" 
			delete-cookies="JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE" 
			logout-success-url="/pages/common/login.jsf"></sec:logout>
	</sec:http>
	
	<sec:authentication-manager alias="authenticationManager">
		<sec:authentication-provider ref="rememberMeAuthenticationProvider"></sec:authentication-provider>
		<sec:authentication-provider >
			<sec:jdbc-user-service data-source-ref="dataSource" id="userDetailsService"/>
		</sec:authentication-provider>
	</sec:authentication-manager>	
</beans:beans>

Since we are using default JDBC template provided by Spring, we don’t have to write any Java Code.
Third we will create our schema.

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';

DROP SCHEMA IF EXISTS `jsf_spring_sec_default` ;
CREATE SCHEMA IF NOT EXISTS `jsf_spring_sec_default` DEFAULT CHARACTER SET latin1 ;
USE `jsf_spring_sec_default` ;

-- -----------------------------------------------------
-- Table `jsf_spring_sec_default`.`users`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `jsf_spring_sec_default`.`users` ;

CREATE  TABLE IF NOT EXISTS `jsf_spring_sec_default`.`users` (
  `username` VARCHAR(50) NOT NULL ,
  `password` VARCHAR(50) NOT NULL ,
  `enabled` VARCHAR(50) NOT NULL ,
  PRIMARY KEY (`username`) )
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;

-- -----------------------------------------------------
-- Table `jsf_spring_sec_default`.`authorities`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `jsf_spring_sec_default`.`authorities` ;

CREATE  TABLE IF NOT EXISTS `jsf_spring_sec_default`.`authorities` (
  `username` VARCHAR(50) NOT NULL ,
  `authority` VARCHAR(50) NOT NULL ,
  INDEX `fk_authorities_users` (`username` ASC) ,
  CONSTRAINT `fk_authorities_users`
    FOREIGN KEY (`username` )
    REFERENCES `jsf_spring_sec_default`.`users` (`username` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;

-- -----------------------------------------------------
-- Table `jsf_spring_sec_default`.`groups`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `jsf_spring_sec_default`.`groups` ;

CREATE  TABLE IF NOT EXISTS `jsf_spring_sec_default`.`groups` (
  `id` INT(11) NOT NULL AUTO_INCREMENT ,
  `group_name` VARCHAR(50) NOT NULL ,
  PRIMARY KEY (`id`) )
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;

-- -----------------------------------------------------
-- Table `jsf_spring_sec_default`.`group_authorities`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `jsf_spring_sec_default`.`group_authorities` ;

CREATE  TABLE IF NOT EXISTS `jsf_spring_sec_default`.`group_authorities` (
  `group_id` INT(11) NOT NULL ,
  `authority` VARCHAR(50) NOT NULL ,
  PRIMARY KEY (`group_id`) ,
  INDEX `fk_group_authorities_group` (`group_id` ASC) ,
  CONSTRAINT `fk_group_authorities_group`
    FOREIGN KEY (`group_id` )
    REFERENCES `jsf_spring_sec_default`.`groups` (`id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;

-- -----------------------------------------------------
-- Table `jsf_spring_sec_default`.`group_members`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `jsf_spring_sec_default`.`group_members` ;

CREATE  TABLE IF NOT EXISTS `jsf_spring_sec_default`.`group_members` (
  `id` INT(11) NOT NULL AUTO_INCREMENT ,
  `username` VARCHAR(50) NOT NULL ,
  `group_id` INT(11) NOT NULL ,
  PRIMARY KEY (`id`) ,
  INDEX `fk_group_members_group` (`id` ASC) ,
  CONSTRAINT `fk_group_members_group`
    FOREIGN KEY (`id` )
    REFERENCES `jsf_spring_sec_default`.`groups` (`id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

Records required to run application.

INSERT INTO `users` VALUES ('admin','admin','1'),('guest','guest','1');

INSERT INTO `authorities` VALUES ('admin','ROLE_USER'),('guest','ROLE_USER'),('admin','ROLE_ADMIN');

Note : – We don’t need all the tables here, since we are not using “Group-Based Access Control” we just need two tables namely Users and Authority.

We are saving plain text password which is not advisable, later we will use Spring to use different encrypting mechanism.

There are 3 comments

  1. Jatin

    This particular functionality of yours is not working. Its accepting the correct usename and password but when wrong credentials are entered it still takes you to the successfully logges in page. Kindly check.

  2. Antonio Lazaro

    I Believe this happens because is missing this in
    sec:jdbc-user-service: users-by-username-query=” select
    username,password, enabled from users where username=? and enabled
    = 1″ authorities-by-username-query=” select u.username,
    au.authority from users u, authorities au where u.user_id =
    au.user_id and u.username =? ” Be like that: If it did’t work,
    review your connection debugging.

Leave a comment