JDBC Realm with Entity Classes

For one of my university modules (specifically SEM5640 - Developing Advanced Internet Based Applications) I've been working to build a Java EE application which, amoungst other features, requires user authentication.

A lot of the guides for setting up JDBC Realms use raw SQL to generate the database. However, because the groups methodology it's easier for us to work with annotated entity classes which create the database automatically for us.

For which of course there's very few full guides.

JDBC Realms can use up to three database tables; Users, Roles and a linking table between the two.

This guide uses Java EE 6 and GlassFish, but I'm sure anyone can extend it to any Java EE application server.

The User Class

To help with things I've used the Apache Common Codec library and for the password hash MD5 is used for simplcity.

Update 7/4/2014 15:54 in response to Sam: yes MD5. It's just example code.

@Entity(name = "USERS")
public class User implements Serializable {  
    @Id
    private String username;

    @Column(columnDefinition = "VARCHAR(32)", length = 32)
    private String password;

    @JoinColumn(name = "ROLENAME")
    @ManyToMany(cascade = CascadeType.ALL, mappedBy = "users")
    private List<Role> roles;

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

    // Other setters and getters
}

The Roles Class

@Entity(name = "ROLES")
public class Role {  
    @ID
    public String rolename;

    @JoinColumn(name = "USERNAME")
    @ManyToMany(cascade = CascadeType.ALL)
    private List<User> users;

    // Setters and getters
}

The web.xml

Java EE also needs a specific configuration to apply the authentication and authorisation to resources. In this case I'm going for a web page in an admin realm.

<?xml version="1.0" encoding="UTF-8"?>  
<web-app version="3.1"  
    xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
        http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <security-constraint>
        <display-name>Administrators</display-name>
        <web-resource-collection>
            <web-resource-name>Admin Pages</web-resource-name>
            <description>Administrator pages</description>
            <url-pattern>/faces/admin/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description>Administrators</description>
            <role-name>Admin</role-name>
        </auth-constraint>
    </security-constraint>
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>SecurityRealm</realm-name>
    </login-config>
    <security-role>
        <description>Administrators of the system</description>
        <role-name>Admin</role-name>
    </security-role>
</web-app>  

GlassFish configuration

Now, GlassFish also needs authentication to map security roles to roles in the database:

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE glassfish-web-app PUBLIC  
    "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN"
    "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">  
  <security-role-mapping>
    <role-name>Admin</role-name>
    <group-name>Admin</group-name>
  </security-role-mapping>

GlassFish Configuration, part 2

And finally, there's some things on the actual server which need configuring to. Go the the admin console (http://localhost:4848 normally) and follow the menus through:

Configurations → server-config → Security → Realms

Create a new realm, with the following attributes:

Name: SecurityRealm  
Class Name: com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm  
JASS: JDBCRealm  
JDBC: jdbc/YourDB  
Users Table: USERS  
User Name Column: USERNAME  
Password Column: PASSWORD  
Groups Table: ROLES_USERS  
Group Table User Name Column: USERS_USERNAME  
Group Name Column: ROLENAME  

And everything should now work :-)