Privacy and security is very important and you really need to consider this at the first time when build and software application, which is lead to design your software application with authentication and authorization for the user. Recently I stumbled on Jerry article about what should and shouldn’t you do about securing password which is very good starting point when you want to build secure software application especially with Java. On Java EE, precisely Java EE 7 and below you will see how hard and not portable to configure authentication and authorization. The good news is, Java Security API finally receive big update and will be shipped on Java EE 8.

As Java EE 7 and below, your option on securing your software application is either depend on application container (application server such as Wildfly or Payara) or using third party library such as Spring Security or Apache Shiro. Today I would like to share my experience on configure Security on Payara 171, and yes this configuration will different with another Application Server.

Securing software application normally you will store your user credentials such as username and password on database and apply some hash or encryption method into the password (because never ever stored password as plain text). Every user need to be assigned on specific permission to restrict what he/she can and can’t do on your software application. So, your first task is design a database for storing user information and I know you will find many example about user and permission table.

Database Design

Before you started to design your table look at this StackOverflow thread.To summarize from that thread, when you want to use Payara security realm, you need to design your permission table have relations to user or it’s a joined table between user and permission table. So, if you want user have only one permissions, make sure the holder of relations is the permissions table. But, mostly user can have more than one permissions this will lead you to make a master-detail table as join table which is my suggestion is create a view table.

create table role(
    id serial primary key,
    role_name varchar(100) not null
);

create table account(
    id serial primary key,
    email varchar(40) not null,
    username varchar(15) not null,
    password varchar(255) not null,
    firstname varchar(100),
    lastname varchar(100),
    active boolean,
    created timestamp,
    updated timestamp
);

create table account_role(
    id serial primary key,
    account_id integer,
    role_id integer,
    foreign key (account_id) references account(id),
    foreign key (role_id) references role(id)
);

create view v_account_role as
select account_role.account_id, account_role.role_id, account_username,
account.password, role.role_name
from account_role inner join account on account_role.account_id = account.id
from account_role inner join role on account_role.role_id = role.id;

Dummy Data

Now you need initial data and of course you don’t want to stored the password as a plain text right? At least use hash and since default hash algorithm on Payara was SHA-256 so make sure the user password was stored after hash with SHA-256 algorithm. You could perform this with Java code like this.

    private String generateSha256(String text) throws NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));
        String encoded = Base64.getEncoder().encodeToString(hash); // Java 8 feature
        
        return encoded;
    }

For example username and password was admin so your query will be look like this.

insert into account(email, username, password, firstname, lastname, active) 
values('admin@mail.com', 'admin', 'jGl25bVBBBW96Qi9Te4V37Fnqchz/Eu4qB9vKrRIqRg=', 'admin', 'admin', TRUE);

Configure Payara Security Realm

To be able use authorization and authentication you must configure security realm, but before that make sure you already create JNDI for database resource since you need to access your database. Access security realm menu on Configuration > Server-Config > Security > Realms and click New button to create new security realm. Make sure to choose JDBCRealm on class name.

new_realm

Below is the example value for the properties and of course following the database above and let some field that not mention below to be empty, the last don’t forget to click Save button.

  • JAAS Context: jdbcRealm
  • JNDI: jdbc/test
  • User Table: account
  • Username Column: username
  • Password Column: password
  • Group Table: v_account_role (yes, use the view table)
  • Group Table Username Column: username
  • Group Name Column: role_name
  • Password Encryption Algorithm: AES (somehow this field not exist on Payara 172)
  • Digest Algorithm: SHA-256
  • Encoding: Base64
  • Charset: UTF-8

With this everything is already done configure on Payara, the next steps was configure your Java EE project.

Create JSF Login Page

On your Java EE project you need to configure so your project will use the security realm from Payara. I give example how to create a login page using JSF so you need to configure your JSF on web.xml file.

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>

Then create simple login.xhtml JSF file that using old j_security_check.

<form action="j_security_check" method="POST">
    <h:outputLabel for="j_username">Username</h:outputLabel>
    <h:inputText id="j_username" size="20" />

    <h:outputLabel for="j_password">Password</h:outputLabel>
    <h:inputSecret id="j_password" size="20"/>

    <input type="submit" value="#{bundle['login.submit']}" />
</form>

Configure Security Configuration

Configure Security Role Mapping

Since you’re using Payara which is derivative from Glassfish you need to create glassfish-web.xml , some tutorials will named it as sun-web.xml but I think glassfish-web.xml is for newest version. For your information this is what I said when the JAAS will be vary for each application server, you need to configure something like this but with a little different of course on another application server such as Wildfly, TomEE or Liberty. Inside of this file will be mapping for the user permissions.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.1//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
    <class-loader delegate="true"/>
    <jsp-config>
        <property name="keepgenerated" value="true">
            <description>Keep a copy of the generated servlet class' java code.</description>
        </property>
    </jsp-config>
    <security-role-mapping>
        <role-name>admin</role-name>
        <group-name>ADMIN</group-name>
    </security-role-mapping>
</glassfish-web-app>

Configure Login Method

Java EE as default provide 5 authentication mechanism like Basic, Form, Digest, Mutual, and Client. Because this authentication using form based you need to specify the Form authentication mechanism on web.xml file.

   <login-config>
        <auth-method>FORM</auth-method>
        <realm-name>TestRealm</realm-name>
        <form-login-config>
            <form-login-page>/login.xhtml</form-login-page>
            <form-error-page>/error.xhtml</form-error-page>
        </form-login-config>
    </login-config>

Configure Security Constraint

The last is specify which URI that need to be protected and which permission that can access the URI. you need to specify this on web.xml file.

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>administrator</web-resource-name>
            <url-pattern>/admin/*</url-pattern>
            <http-method>POST</http-method>
            <http-method>GET</http-method>
            <http-method>PUT</http-method>
            <http-method>DELETE</http-method>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>

The Conclusion

Seeing how not portable the current JAAS API, I really excited with the new Security API which proclaimed will standardized the security API so moving to another application server won’t be pain anymore.

Momentarily, I just know Payara support Hash to protected the password but it will be great if you can use encryption method such as PKBDF2 or Bcrypt. Since I can’t found any decent tutorial using encryption for the password.

Actually, I have interest on Apache Shiro which proclaimed the easiest security frameworks but sadly I still can’t found any decent tutorial for implementing Apache Shiro into Java EE project from scratch until the end. But I will recommend to using this if you want to avoid JAAS on Java EE project below version 7.