/ AUTHENTICATION

Authentication alternatives in Java EE webapps

I started developing on the Java EE platform 15 years ago (yep, you read that right). At that time, the only way to authenticate in a webapp was through a callback. Recent Java EE versions offer alternatives.

This post aims at describing both, how they work and their respective benefits.<!--more-→

The legacy way

The way available since J2EE 1.3 (and perhaps earlier, but then I’m not an archeologist) is through a callback mechanism: the platform only asks for a user’s credentials when he tries to access a protected resource. If credentials are accepted, then the user is authenticated. Then his access rights are matched to the access rights required to acces the resource. If they match, he’s allowed to; otherwise, he receives a 403 error.

This raises a few questions:

  1. what is a resource?
  2. how to attach access rights to a resource?
  3. how to ask a user for credentials?
  4. how to configure access rights of a user?
  5. how to logout?

Resources and roles

In Java EE webapps, resources are plain URLs:

  • admin
  • secure/configure
  • etc.

Resources can be grouped, using a simple pattern (it allows * at the beginning or the end, but not more).

To protect a resource or a group of them, one associates it with a role. A role is just a string.

Both roles and their associated resources are configured in the web.xml deployment descriptor:

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Administration</web-resource-name>
            <url-pattern>/administration/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>
    <security-role>
        <role-name>admin</role-name>
    </security-role>
</web-app>
Roles must be declared in a separate <security-role> tag, before being used in <security-constraint>.

Asking for credentials

Java EE offers 4 ways to authenticate:

  • Basic
  • Digest
  • Form
  • and Client certificate

We will cover only Basic and Form, as they are the most used.

Basic

Basic authentication is based on the browser. When an unauthenticated user attempts to access a protected resource, the platform returns a 401 HTTP status code. The browser intercepts the response, and displays a native popup asking for login and password credentials. If credentials check fail, then the user is shown the popup again, until they succeed.

Whether the authenticated user can access the resource or not depends on his role(s).
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
  <login-config>
    <auth-method>BASIC</auth-method>
  </login-config>
</web-app>
Form

Form authentication is based on the server. When an unauthenticated user attempts to access a protected resource, the platform returns the configured login form.

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
  <login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
      <form-login-page>/WEB-INF/page/login.jsp</form-login-page>
      <form-error-page>/WEB-INF/page/error.jsp</form-error-page>
    </form-login-config>
  </login-config>
</web-app>

Logging out

In the old days, the way to log out an authenticated user very was straightforward:

response.invalidate();

Unfortunately, the above line effectively destroys everything that was stored in the session, including data unrelated to authentication, such as user preferences (e.g. theme).

Using annotations

The version 3 of the Servlet API takes advantage of annotations and allows to use them to restrict roles allowed to access a servlet.

For example, the following is the equivalent of the first XML snippet:

@WebServlet("/adminstration/foo")
@ServletSecurity(
    @HttpConstraint(rolesAllowed = "admin")
)
public class FooServlet extends HttpServlet {
}

Obviously, it works very well for one specific servlet. However, if different servlets need to be protected by the same role, then the annotation has to be replicated on each of them.

The programmatic API

The main issue with the authentication callback described above is that it was designed for page-based navigation in mind. If the webapp is a Single-Page Application, URL handling tricks are necessary to make it work.

Permission checking

Java EE allows to guard URLs, or even URL/HTTP method pairs. For SPAs, this is not enough. Even in traditional webapps, the different doXXX() methods might not be granular enough for some use-cases. Also, sections of JSPs might be different depending on the user role.

Hence, the Servlet API offers the HttpServletRequest.isUserInRole(String role) method to check whether a user has a specific role or not.

JSTL offers no out-of-the-box equivalent for that.

Authenticating

Like for checking, authentication callbacks bound to URLs are not easily integrated with SPAs. To handle that, the Servlet API v3 offers the HttpServletRequest.login(String username, String password) method to programmatically authenticate the user.

The symmetric HttpServletRequest.logout() method allows to un-authenticate an authenticated user without losing data stored in this user session.

Conclusion

As always, it pays to know tools available. And for that, it’s necessary to keep up-to-date with the latest changes in the API.

Nicolas Fränkel

Nicolas Fränkel

Nicolas Fränkel is a Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with narrower interests like Software Quality, Build Processes and Rich Internet Applications. Currently working for Exoscale. Also double as a teacher in universities and higher education schools, a trainer and triples as a book author.

Read More