JavaData & JavaPassword Hashing Using JAAS

Password Hashing Using JAAS

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Integrating authentication services into your Web apps is a serious business. Serious both in terms of demand and repercussions of doing a sloppy job. For best results, it’s best to use a tried and true library. If you’re working with Java, the Java Authentication and Authorization Services (JAAS) is well worth considering. In the Implementing Java-based User Authentication with JAAS article, we learned some of the nuts and bolts of JAAS. Although that was a good introduction, in the real world, you need something a bit more robust. In today’s article, we’ll write a utility for storing the user credentials into a database with a hashed password.

About the Database

For the purposes of today’s tutorial, we’ll be using the outstanding and completely free MySQL database. The user ID and password will be saved to a table named “users”, which resides in a database named “test”. Any database will work, so feel free to substitute another. Here is my CREATE statement:

CREATE TABLE 'test'.'users' (
   'id'       INT NOT NULL,
   'username' VARCHAR(10) NOT NULL,
   'password' VARCHAR(45) NOT NULL,
PRIMARY KEY (id));

The id primary key is required for JPA.

The persistence.xml File

This file includes definitions for one or more Persistence Units, which each in turn contain a number of properties and attributes that are necessary to connect to the underlying data store. I already spoke at length on the subject in my Defining JPA Persistence Units in your Java Enterprise Applications article, but I would like to reiterate that you must include the persistence.xml file on the classpath in a folder named “META-INF”. I recommend creating a separate source folder named “resources” and add the META-INF folder under that:

Hash1
Figure 1: Project structure

Here are the contents of my persistence.xml file. It includes the persistence-unit name, my Entity class, MySQL driver and database info, and login credentials.

<persistence xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi_schemaLocation="http://java.sun.com/xml/ns/persistence
      http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
   version="2.0" >
   <persistence-unit name="user" transaction-type="RESOURCE_LOCAL">
      <class>com.robgravelle.jaasdemo.User</class>
      <properties>
         <property name="javax.persistence.jdbc.driver"
                   value="com.mysql.jdbc.Driver" />
         <property name="javax.persistence.jdbc.url"
                   value="jdbc:mysql://localhost/test" />
         <property name="javax.persistence.jdbc.user"
                   value="user_admin" />
         <property name="javax.persistence.jdbc.password"
                   value="UserAdm1nPa$$90" />
         <property name="eclipselink.ddl-generation"
                   value="create-tables" />
         <property name="eclipselink.ddl-generation.output-mode"
                   value="database" />
      </properties>
   </persistence-unit>
</persistence>

Configuring the Driver

Whatever database you use, Java requires a driver to connect to it. For instance, MySQL requires the Com.Mysql.Jdbc.Driver contained in the Mysql-Connector-Java-5.1.25-Bin.Jar file (the exact name may differ depending on the latest version). Download it and add it to your project libraries.

Java and Project Requirements

JPA is packaged with Java Enterprise Edition (EE) so you should develop in the Eclipse IDE for Java EE Developers. Moreover, your project has to be a “Dynamic Web Project.” That will automatically include the JPA libraries.

Saving the User Credentials

You could just add new users to the “users” table as you would with any data, but that would leave the passwords in clear text. The secure approach is to encrypt it by using a hash and compare user logins to it after first running the input field through the very same algorithm. For that reason, we’ll use a class that does the hashing by using the MD5 algorithm. Our UserCredentialsUtility calls it to hash the user password before committing it to the database.

package com.robgravelle.jaasdemo;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class UserCredentialsUtility {
   // The factory that produces entity manager.
   private static EntityManagerFactory mEmf =
      Persistence.createEntityManagerFactory("user");
   // The entity manager that persists and queries the DB.
   private static EntityManager mEntityManager =
      mEmf.createEntityManager();

   public static EntityManager getEntityManager() {
      return mEntityManager;
   }

   public UserCredentialsUtility() {}

   public static void main(String[] args) {
      User user = null;
      try {
         mEntityManager.getTransaction().begin();

         user = new User("myName", "myPassword");
         mEntityManager.persist(user);

         mEntityManager.getTransaction().commit();

         System.out.println("User successfully saved.");
      } catch (Exception e) {
         System.err.println("Couldn't save the user info: "
            + e.getMessage());
      }
   }
}

The User Entity class is a typical model class, but with the extra getMD5Hash() method. It employs the native Java MessageDigest class to produce the hash.

package com.robgravelle.jaasdemo;

import java.io.Serializable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

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

@Entity
@Table(name = "users")
public class User implements Serializable {

   private static final long serialVersionUID =
      -7015126518949115540L;

   @Id @GeneratedValue
   private Long   id;
   private String username;
   private String password;

   public User() {}

   public User(String username, String pw)
         throws NoSuchAlgorithmException {
      this.username = username;
      this.password = getMD5Hash(pw);
    }

   public long getId() {
      return this.id;
    }

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

   public String getUsername() {
      return username;
   }

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

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

   public String getPassword() {
      return this.password;
   }

   public static String getMD5Hash(String input) {
      StringBuffer sb = new StringBuffer();

      try {
         MessageDigest md =
            MessageDigest.getInstance("MD5");
         md.update(input.getBytes());
          byte[] mdbytes = md.digest();

         //convert the byte to hex format
         for (int i = 0; i < mdbytes.length; i++) {
            sb.append(Integer.toString((mdbytes[i] & 0xff)
               + 0x100, 16).substring(1));
         }
      } catch (NoSuchAlgorithmException e) {
         e.printStackTrace();
         System.exit(-1);
      }

      return sb.toString();
   }
}

The UserCredentialsUtility in Action

Barring any unexpected glitches, running the UserCredentialsUtility saves our user to the database with a password that is properly obfuscated.

Hash2
Figure 2: Users table

Conclusion

That takes care of the credentials generation side of things. In the next installment, we’ll develop the login code that validates input fields against those of the users table.

About the Author

Author

Rob Gravelle resides in Ottawa, Canada, and is the founder of Gravelle Web Design. Rob has built systems for Intelligence-related organizations such as Canada Border Services, CSIS, as well as for numerous commercial businesses.

In his spare time, Rob has become an accomplished guitar player, and has released several CDs. His band, Ivory Knight, was rated as one Canada’s top hard rock and metal groups by Brave Words magazine (issue #92) and reached the #1 spot in the National Heavy Metal charts on Reverb Nation.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories