Playing with Java EE Security (JSR-375) — Soteria

Programmatically Custom Form Authentication with Remember Me.

To be honest, JavaEE is rock. Even though my experience with JavaEE is less than two years, yet I’m not find any difficulty while hacking with JavaEE. I already satisfied with current JavaEE 7, with so many useful API I could build simple web applications, REST API, even I still can build SOAP Web Service using and only JavaEE 7. I’m happy with JavaEE 7 but as you know JavaEE 8 will come soon, since JavaEE 8 is almost reach the Final Approval Ballot. With so many awesome feature, I believe JavaEE 8 will improve your productivity more further. Among those awesome specification, actually I already stared on one of JavaEE 8 specification from long time ago, it was JSR-375, JavaEE security specification.

I have experience how bothersome to configure security on JavaEE applications and stated should I keep using the standard which is actually not standard or move away and use third party security frameworks, but finally with JSR-375 I can hope to have something that more standard and simple way to configure security on JavaEE. After long time studied about JSR-375 from their example source code, read long and descriptive information about security API from Mr. Arjan Tijms, and with a little help from this wonderful javaee kickoff application finally I could understand and can build simple JavaEE application with JSR-375. So, I would like to share my experience when toying with JSR-375 API.

Preamble JSR-375

Despise many people said that JSR-375 is still need more improvement, but in my opinion the current JSR-375 is already good. Before we move further I would like to state some important information regarding JSR-375 and mostly I just cited from Mr. Arjan Tijms explanations.

Identity Store

Talking about security was not separated from authentication and authorization which is you need to check whether the user can access your applications or not (authentication) and you also need to check what kind of access this user can do in your application (authorization). Usually, and most people will store this user information on database such as username, email, password, role and permission. You only need to compare if the user information was match or not, and this is the responsibility of Identity Store. Identity Story don’t have effect on the authentication mechanism, it’s only work as data repository or database.

Authentication Mechanism

JSR-375 is really backward compatibility, knowing that it’s support Basic Authentication, Form Authentication and even JASPIC. Authentication Mechanism is like the heart of JSR-375, because this API was responsible to check whether the user is authorized or not. The implementation in my opinion is very simple and good, though they made every request will be checked by Authentication Mechanism, but with only @AutoApplySession you don’t need to put @SessionBean on your class that implemented HttpAuthenticationMechanism , it have been done by that convention.

Remember Me

I remember very well that the oldest JAAS and JASPIC not support well remember me feature, this is made me rethinking to use another frameworks. Now, with JSR-375 that also supported remember me, I would confident enough to keep with JavaEE standard.

Those three is the major feature that made JSR-375 powerful and with this I would like to share my experience in building simple JavaEE with JSR-375. The applications won’t have complicated feature, it will only block unauthorized user until he / she register and login. The user also won’t have complicated Role and Permission which is I found that very low article to provide explanation how to do authentication with user that don’t have Role and Permission.

Simple JavaEE Project

Even though JSR-375 will bundled on JavaEE 8, it’s not mean you can’t use it on JavaEE 7. What you need is simple JavaEE 7 project and then add JSR-375 API implementation, Soteria, on your dependency. I’m using Maven to generate JavaEE 7 project, and I declare the dependency on my pom.xml. Since I want to build programmatically form authentication, I would use simple JSF as for the login page. Knowing you will work with JSF, I would like to add Omnifaces dependency to made more easy work with JSF. So, your dependency on pom.xml would look like this.

<dependencies>
<!-- Java EE API -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>

<!-- Security API Soteria -->
<dependency>
<groupId>org.glassfish.soteria</groupId>
<artifactId>javax.security.enterprise</artifactId>
<version>1.0-b07</version>
</dependency>

<!-- Omnifaces, develop JSF never easier without Omnifaces -->
<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces</artifactId>
<version>2.6.4</version>
</dependency>
</dependencies>

Structure Data / Database Schema

The application should be able to distinguish between authorized user (which is prove that he / she can login into the application) and not. You need to store the user credentials in order to check if the user was match or not. Since you will also implement remember me feature, you need to store the remember me session too.

As you know, there is simple different between session (e.g. the well know JSSESSIONID) and remember me session that you want to build. The session ID was backed from volatile memory on the front-end and it not last long (approximately 30 until 60 minutes) while session of remember me should be longer than that, which is you will need a database to store this session.

Now, for the sake of simplicity you will have two tables Account and Token I hope from the name you will be able to know what the used of those table. Your Account table should store the most important data from your user like username, password, email and active status from the user.

CREATE TABLE account(
id INTEGER PRIMARY KEY,
username VARCHAR(100) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
active BOOLEAN
);
CREATE TABLE token(
id INTEGER PRIMARY KEY,
account_id INTEGER REFERENCES account(id),
token_hash VARCHAR(255) NOT NULL,
token_TYPE VARHCAR(100),
ip_address VARCHAR(100),
description VARCHAR(255),
created TIMESTAMP,
expiration TIMESTAMP
);

Hashing

Hash is also a fundamental in security, you don’t want to store your user password as plain text, right? Also, remember me cookie was essentially key to your user credentials which is really need to be guarded carefully. On this application hashing will be used on password and the remember me cookie. Actually JSR-375 is already provided hash algorithm if you check from this example. The bad news, the implementation of hash algorithm on Soteria was on version 1.0-b13-SNAPSHOT , and the latest release version as you can see on the pom.xml was version 1.0-b07 .

Don’t worry, you still could apply hashing algorithm such as Secure Hash Algorithm (SHA). Actually, there is something I’m not quite sure. On this wonderful project they use SHA-256 to hash the remember me cookie session, but I would feel safe to implement SHA-512 to hash user password. I wonder, what is the harm to use SHA-512 on hashing remember me cookie session? But in my opinion maybe it’s related to performance issue, so in this application you will have both algorithm to hash the password and remember me cookie session and of course I will show you how to made it.

Since you’re using JavaEE and for the sake of Don’t Repeat Yourself (DRY), you can build a CDI Qualifier on this matter. First, you need to create the HashGenerator class that provide how the hash method working.

Class that responsible to generate hash

Since you will use SHA-512 and SHA-256, I suggest to made an Enum to hold the value of the algorithm name.

Next create the Qualifier annotations.

Java CDI Qualifier

You could see, I made the default value was SHA-512 which is I made convention over configuration. When you not declare the algorithm name, as the default it will use SHA-512.

The last was create Producer to be able configure the Injection using annotation parameter value.

AlgorithmProducer to provide Injection Qualifier configuration.

With this, you can use the HashGenerator easily like this.

@Inject @HashAlgorithm(algorithm = Algorithm.SHA256)
HashGenerator hash;

Business Process to Retrieve, Store and Validate Account and Token

Next before you could implement JSR-375 you need to prepare the business process like store, retrieve and validate account and token, I will show you step by step on build this.

JPA Entity

Let’s started build Token entity, first you need to define the TokenType as Enum, why I do this because in the future the Token would not only store remember me cookie session but you can use it for another case, for example REST Token, session to reset password or activate user account.

Next, while make the Token entity, remember that it have relations with Account entity.

In order to made no error, you need to create Account entity as well.

EJB Service

Next I will show you minimum EJB Service that you need to made in order to do registration new user, login, check if the user is authorized or not and of course generate remember me cookie session.

You will create two service, first for the Account and next for the Token below is the service for the Account.

Then below is for the Token service.

From source code above, you must see that I made custom expection. Actually is just an RuntimeException and since Exception was wraped on EJB it won’t roll-back if something happen. So, in order to keep the acid data on EJB I create custom exception.

import javax.ejb.ApplicationException;
@ApplicationException(rollback = true)
public abstract class BusinessException extends RuntimeException {
}

Then I just need to extends my custom exception like this.

public class InvalidUsernameException extends BusinessException {
// nothing to do here
}

Implementing FormAuthenticationMechanism with RememberMeIdentityStore

Now, it’s time to hacking with Soteria, JavaEE JSR-375 Implementation API. Like I explain before, you will build FormAuthenticationMechanism with RememberMe feature. But before you implemented that, first you need to implement IdentityStore in order to validate the Credentials.

IdentityStore

IdentityStore implementation

Like I said, IdentityStore is simple interface that responsible on check whether the credentials is valid or not, the credentials can be UsernameAndPasswordCredential or CallerOnlyCredential both should return CredentialValidationResult. This CredentialValidationResult must return the status code, the new caller, and optionally the caller role.

return new CredentialValidationResult(VALID, new CallerPrincipal("sukma"), asList("foo", "bar"));

In your case, you need to add one more validation whether the user is already activate or not which why I made validate method. I’m not define the status code since I will follow the default and I only need to put the caller credentials, it can be username, or name of the user and since this application don’t have permission you don’t need to put the role.

RememberMeIdentityStore

RememberMeIdentityStore implementation

Next was implement the RememberMeIdentityStore , this class will be execute if your user decided to use remember me feature. Actually method generateLoginToken not specify said to store the token into database, you only need to return the token and everything is work, but like I said earlier you need to guard the remember me cookie session and then store it on the database which is have been done in EJB TokenStore.

HttpAuthenticationMechanism

HttpAuthenticationMechanism implementation

This was the core of the JavaEE security, every HTTP request that come from servlet will be protected from here. I would like to give some comment in here regarding @RememberMe , in sample project of Soteria I see they’re using EL on isRememberMeExpression like this: #{self.isRememberMe(httpMessageContext)} which is not work, I think it’s because the different version of the Soteria API or they’re using some EL dependency that I’m not used. Therefore, I found another EL that work well on this project that is using this instead of self.

JSF Programmatically Authentication

Security implementation is important, but don’t forget that you need to provide a way for the user to authenticate him / her self. Which is the next steps was build Registration and Login page, and of course use JSF, sadly this tutorial still using JSF 2.2.

Registration Page

Before the user could authenticate, of course first they need an account on your application, right? which is the first JSF page that need to made is Registration page. Below is JSF Managed Bean for registration page.

Next, let’s create the JSF page. I’m not good in styling so what can I made is very simple registration page.

Login Page

Now let’s made the login feature, the JSF bean for login was like below.

You can see the SecurityContext it come from JavaEE Security API that responsible to validate user credential such as username (or you can use email in here) and password. When method authenticate from SecurityContext was executed if the user was authorize it will automatically create the session and if the user thick the remember me, it will also triggered the RememberMe annotations to generate the remember me cookie session.

The login page was simple, it will consist with username, password and remember me field that can be used to authenticate towards security mechanism.

Protect the HTTP Request

This is the trickiest part as for me, so far, I already tell you how to authenticate and check if the user have the privileges or not towards your application. The next steps was how to prevent unauthorized user to access your applications? I’m not quite sure how to do this since almost all the security sample projects using simple example with only one WebServlet , finally after stumbled on this StackOverflow discussion I decided to build WebFilter to protect the HTTP request.

Since JavaEE Security was working on top Servlet, implement javax.servlet.Filter is the easiest way to protect your applications. Since the authentication responsibility was done by JSR-375 in your filter you only need to check whether the user is authorized or not, so you not re-invented the wheel. Below is how the filter look like and it’s heavily depend on Omnifaces to reduce some boilerplate code.

Now with this you already secure every HTTP request under /* and unless you specify to exclude some URL every unauthorized user will be redirect towards login page. On the filter class there is not much to do and only doing check towards the request.

The Conclusion

So far, I’m really satisfied with JSR-375, my expectation to have a standard JavaEE security API was fulfilled by JSR-375. Even there is some people that said this specification was far from perfect yet is much more better to have an initial standard since security is most fundamental when building and application.

The last, I’m not an expert and my experience with JSR-375 is not considered to long, so I will gladly to accept any feedback and response. Hope this simple article can help you to prepare when you want to adopt JavaEE 8 that soon will be arrive.

If you enjoyed reading this article, please recommend with click the 👏 below and share it to help others find it!