There are many blogs explaining how to get Jakarta Security on Tomcat using all sorts of libraries and wiring everything manually. So many opportunities to get it wrong, if you are evaluating or currently using Apache TomEE.
In TomEE, the good news is that, like JAX-RS, CDI or Bean Validation, Jakarta Security is out of the box ready to be used like Servlet, and CDI for example.
This blog is a high-level view so you have the big picture of the technologies and how they interact with each other in the security landscape. The goal is to be able to use them when needed, and quickly!
If you are looking into something detailed for each technology, I would suggest joining the mailing lists for the different Jakarta projects and get in touch with the committers. Good opportunity to contribute now that everything is open sourced. For further TomEE contributions or inquiries, you can also join the TomEE mailing lists.
Why is Jakarta Security important?
Jakarta Security API (code name JSR 375) first appeared quite recently, in Java EE 8. Most people would say, it’s been on the platform for quite a long time. Why is there a need for another specification?
First, it actually took over 20 years for Java EE to start having some kind of lightweight security for applications. Before that, the only thing available was in Java SE to secure the code itself, and that was mainly in the context of the Applets because they were running on the client-side. On a regular Java EE / Jakarta EE environment, the code is trusted as it is ours and it’s also running in our trusted environment (static user with static permissions or roles depending on the environment they were running in). So I don’t know if many companies are really using that. What needs to be addressed, in this context, isn’t how to secure the code itself, but who is calling us, and what can he/she do.
Servlet and Principal
The first notion of Principal and roles appeared in a very light, blurry, and hard-coded manner in the Servlet specification (J2EE 1.2). It’s still there today, security roles and security constraints defined in the web.xml, some HttpServletRequest request methods to retrieve the Principal or to test if a user has a role or not. Then, in terms of authentication, a finite list of hard-coded values (like BASIC, FORM, etc), that each implementation could implement the way they wanted. Even in Tomcat, until recently at least, the concepts of Realm and Authenticator were hardcoded and not extensible. With these improvements based on the Servlet specification, users and roles were a variable, but there was nothing specified for the authentication mechanisms. So each server was doing its own thing, again preventing any kind of portability.
JAAS (Java Authentication and Authorization Service)
It is only in J2EE 1.4, that an answer was given with JAAS. At first glance, it looked like the missing part of the puzzle was to implement user centric security in Java EE. In practise, it added a bit more fuzzy zone allowing application servers to keep implementing their own stuff. For example, JAAS did not really define how to assign Login modules to a specific application. It did not mention, either how to distinguish between the Principal returned by the getUserPrincipal, or the list of Principals representing the roles. And finally, still, nothing to address the notion of identity store where users and roles will be stored.
One gap was filled in J2EE 1.4 with JACC (explained here after). It took out some misunderstandings and unspecified areas, especially on how to model URL constraints in Servlets, and the same for method permissions in Java SE (yes, back to the beginning lol). Even though it allowed some clarifications, it also introduced a significant complexity draining all the efforts.
For some reason, it took another 10 years after Servlet security was introduced, for the Java platform to realize the authentication part never got addressed. JASPIC was added very recently in Java EE 6. It really added value by clarifying the interfaces and standards around authentication mechanisms. Again, something was missing, it was the ability for an application to register an authentication module. Tomcat 8.5, for instance, implemented JASPIC, and allowed such a thing with a jaspic-provider.xml configuration file.
JACC – Authorization
In France, we have a well known joke, “Pourquoi faire simple quand tu peux faire compliqué ?”, which literally means, “Why should you do it simple when you can do it complicated?”
This has always been my feeling with JACC (Java Authorization Contract for Containers). It was added back in J2EE 1.4 to define a contract between Java EE application servers and an authorization policy provider. This is, in essence, an entry point that allows you to define your own java.security.Permission classes. It got a few minor updates over the course of the Java EE releases, but nothing that makes it easier to understand.
If you start asking around, you will probably get the answer, “I have no idea what this thing does and what it’s for”, and that’s putting it politely.
JACC provides you with a hook into the authorization process. I said only authorization, aka can the user/caller access resource A (a web URL for instance). It does not, at all, address the authentication part (identify the caller and make sure it’s the person it’s pretending to be).
Then, there is the part to actually use it:
- Like in Servlet, EJB or JAX-RS, you can get at any time the caller/user logged in. In this case, you will simply do `Subject subject = (Subject) PolicyContext.getContext(“javax.security.auth.Subject.container”);`
You can, of course, realize that:
- In EJB, you would get SessionContext (or any other subclass of EJBContext) injected so you could call `getCallerPrincipal()`. It returns a Principal and not a Subject.
- In Servlet, you can, from the HttpServletRequest call, `getUserPrincipal()`. It also returns a Principal. Notice that it’s user, and not caller, for HttpServletRequest.
- In JAX-RS, you can get the jakarta.ws.rs.core.SecurityContext injected (be careful with the package as there are more …) and then call getUserPrincipal().
JASPIC – Authentication
Arjan Tijms summarizes it as “It’s a thin API that enables building fully standardized and pluggable authentication modules”.
The primary goal was to create a standard interface for Servlet containers supported mechanisms. Even though today, most of the Servlet containers such as Tomcat (and therefore TomEE) or Jetty support JASPIC, the adoption of it was very slow.
Like any specification in the early days, JASPIC had its own set of issues:
- Too generic because we wanted it to be flexible and usable for any kind of application and authentication,
- But there was no way for an application to register its own authentication module.
In the end, portability was impossible most of the time. And even more so, because the TCK is lacking coverage in that area, which means everyone can pretty much claim to be compliant.
Java EE 7 came with an updated version of JASPIC, 1.1 to fix those issues and also clarify some interaction with the Servlet API.
So what’s up with Jakarta Security API?
Jakarta Security API depends on JASPIC and is implemented as a JASPIC authentication module. The goal was to use JASPIC under the cover, but address issues especially the ability for an application to configure its security. This is, of course, particularly important for cloud deployments, because we don’t want anything outside of the war deployment.
The goal was also to remove all unspecified parts leading to vendors having their own configuration, solutions for very simple things like:
- switching from one identity provider to another
- switching from Basic to Form authentication mechanism
- applying session to propagate authentication to subsequent http requests
- supporting remember me
Did you find this blog useful? Get ready for the next couple of blog posts that are going to technically demonstrate some of the features of Jakarta Security with TomEE.