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

Programmatically Custom Form Authentication with Remember Me.

With release of Java EE 8, the reference implementation of JSR 375, Soteria reach stable version (1.0). I update this article using the latest stable version of Soteria. Added how to run this project with WildFly Application Server.

To be honest, Java EE is rock. Even though my experience with Java EE is less than two years, yet I’m not find any difficulty while hacking with Java EE. I already satisfied with current Java EE 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 Java EE 7. I’m happy with Java EE 7 but as you know Java EE 8 will come soon, since Java EE 8 is almost reach the Final Approval Ballot. With so many awesome feature, I believe Java EE 8 will improve your productivity more further. Among those awesome specification, actually I already stared on one of Java EE 8 specification from long time ago, it was JSR-375, Java EE security specification.

I have experience how bothersome to configure security on Java EE 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 Java EE. 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 Java EE 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 Java EE 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 Java EE Project

Even though JSR-375 will bundled on Java EE 8, it’s not mean you can’t use it on Java EE 7. What you need is simple Java EE 7 project and then add JSR-375 API implementation, Soteria, on your dependency. I’m using Maven to generate Java EE 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</version> <!-- Stable 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. The DDL below was specified for PostgreSQL database.

CREATE TABLE account(                          
id SERIAL 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 SERIAL PRIMARY KEY,
account_id INTEGER REFERENCES account(id),
token_hash VARCHAR(255) NOT NULL,
token_TYPE VARCHAR(100),
ip_address VARCHAR(100),
description VARCHAR(255),
created TIMESTAMP,
expiration TIMESTAMP
)

Hashing

This section is still applicable, but if you want to explore hash feature on JSR-375 you could check it on here.

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. I’m still explore about this feature, hope I could share when I could understand how to use it.

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 Java EE 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.

Provide Secure Hash Algorithm (SHA).

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.

Having feature to remove expired token on TokenStore is still not sufficient, because you need something to trigger it and this is the perfect time to use Schedule from EJB and below how is the scheduler for removing an expired token.

The scheduler was activate each hour on everyday.

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

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

Then you only need to extends the 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

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

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

This was the core of the JavaEE security, every HTTP request that come from servlet will be protected from here.

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.

Logout Page

Next you need to create a Logout feature for the user (Unfortunately I was forgot about this feature until Stefan Naujoks mention it). The logout feature to be honest a little bit depend on Omnifaces, below was how its JSF logout bean look like.

Then you could define the logout as commandButton or commandLink depend on your case, I would give simple commandButton example for the JSF page.

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 Java EE 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.

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.

WildFly Application Server

Recently, I have report from Quang which is this tutorial not work properly with WildFly application server. Then after do some research, I found that you need to activated JASPIC on Jboss 7 or WildFly 10 and above. You could read to whole information from Mr. Arjan blog.

The simple solutions for WildFly 10rc5 and above was create a jboss-web.xml file under src/main/webapp/WEB-INF which the content of jboss-web.xml look like this.

<?xml version="1.0"?>
<jboss-web>
<security-domain>jaspitest</security-domain>
</jboss-web>

The Demo

When you reach until this sections, then everything is done. The next and last steps was try your project :)

Build on top Maven build tools, you could build your war file using command mvn clean install and you will see your war file on directory target . Depend on your Application Server about how to deploy your war file, on this example was using Payara application server. Put your war file on directory PAYARA_HOME/glassfish/domains/YOUR_DOMAIN/autodeploy then start the Payara application server with command ./asadmin start-domain (this is for nix environment).

When everything is done, you browse your project on http://localhost:8080/<project_name> Because of the ServletFilter the initial page that you see will be login page, but knowing you don’t have any data on your database first you need to register your account on registration page.

registration page

Actually, in real world application the new account should have attribute not active. The user need to activate their account over clicking link that provide by the application, but for the sake of this example the account was activate as the default value. Now, after finish with registration, you could start to log in to see index page.

login page.

When you thick the Remember Me box it would made your account could access the index page as long as the token was not expired. When you’re not thick the Remember Me box automatically you will use JSSESSIONID sessions.

The Conclusion

So far, I’m really satisfied with JSR-375, my expectation to have a standard Java EE 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 Java EE 8.

The complete project can be found on here.

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