Java EE 8 introduced a new API called the Java EE Security API (see JSR 375) or "EE Security" in short.
This new API, perhaps unsurprisingly given its name, deals with security in Java EE. Security in Java EE is obviously not a new thing though, and in various ways it has been part of the platform since its inception.
So what is exactly the difference between EE Security and the existing security facilities in Java EE? In this article we'll take a look at that exact question.
History of Security in Java SE
Originally the security model in Java SE focussed on code level, assuming the user is simply the owner of the (desktop) computer and the code in question is alien and possibly hostile to the user's computer. This model makes a lot of sense for Applets, which are essentially small applications downloaded to the user's computer from a webpage and executed from there. This model makes less sense however in Java EE, where basically the opposite holds; the code running on the server is trusted, while the users are external and possibly hostile.
Java was relatively late with introducing any kind of security model or API focussing on users and permissions of those users. It's not as if such model wasn't known in the early days of Java, as systems like Unix had obviously implemented things like that for a long time. Particularly peculiar perhaps is that the pre-J2EE versions of Servlet, such as Servlet 2.1 from November 1998, had no notion of security other than the getRemoteUser() which simply represented a string sent by the client.
When the first version of J2EE was released in December 1999 (somewhat confusingly versioned at 1.2 to align with the current J2SE 1.2 version of the time) it included a basic user (principal) based security system for Servlets. Particularly remarkable is that in the 20 years prior there have barely been any changes or additions to this small, but functional, API in Servlet.
Particularly, Servlet 2.2 in J2EE 1.2 (which was basically the 1.0) added:
- Opaque security roles (essentially 2 levels; application-wide and per Servlet)
- Constraints on URL patterns, expressed in web.xml
- HttpServletRequest.isUserInRole() method
- HttpServletRequest.getUserPrincipal() method
- Four hard-coded, non-extensible authentication mechanisms: BASIC, FORM, CLIENT-CERT and DIGEST
These things were mostly defined in a rather open-ended way. Roles for instance were more or less supposed to be mapped to other roles that were available in the environment in which an application was deployed. To distinguish these environment roles from application roles, the environment roles were early on called "groups". It's a question though whether this different term indeed clarified the situation or only made it more unclear.
Constraints, though relatively straightforward, lacked a tight formal specification in the first version, which hurt portability as different vendors interpreted the rules in different ways. Specifically unclear was how to deal with overlapping constraints.
Furthermore, no specific interface or class was defined for the authentication mechanisms. The spec just defined that BASIC etc had to be there, without even assuming there was a proprietary class corresponding directly to it. For instance, in 1999 Tomcat 3 (which is more or less the first release of the product as we know it today), had a single class called AccessInterceptor that just did an if/else on the authentication mechanism aka authentication method aka login type (people in security absolutely love to have multiple terms for just about everything):
At around the same time, the JAAS framework was being introduced for Java2 SE. Initially as an extension for 1.3.1, and then included with 1.4. On the surface, JAAS seemed to compliment the Servlet security model perfectly, with its support for user-centric, principal based security.
In practice however, things weren't so clear cut, as it wasn't obvious at all how JAAS should be integrated into Java EE. Particularly troublesome were how and where it should be specified which LoginModule a given application should use, how application code should get a hold of the Subject, how to retrieve the Principals representing the user/caller (the one to be returned by HttpServletRequest.getUserPrincipal) and how to obtain the Principals representing the roles (the ones to be tested for by HttpServletRequest.isUserInRole).
All these things (together the "identity store responsibilities") however still needed to be done, so all servers implemented that in a different way.
Delays of JASPIC Release
This all was supposed to be cleaned up for Java2 EE 1.4 (late 2003). It would be based on Java2 SE 1.4 which included JAAS, and two specs were targeted for Java2 EE 1.4 to solve the integration questions; JACC in 2001 for the authorization part, and JASPIC in 2002 for the authentication part.
JACC indeed made it into Java2 EE 1.4 , but JASPIC was mysteriously delayed, and so much delayed that it even missed the Java EE 5 release, only to finally make it into Java EE 6 in late 2009, a whopping 10 years after Servlet had initially introduced the declarative security model.
Early Issues with JACC
While JACC was introduced on time, and succeeded quite well in modeling constraints on URLs and methods as Java SE Permissions, and by doing that was able to unambiguously define the rules that the Servlet constraints were already using. This resulted in a new section in the Servlet spec that took away the ambiguity with overlapping constraints. Despite this success, unfortunately JACC also came with quite a bunch of issues. Particularly having to build a complex authorization module completely from scratch for every little modification to the default algorithm and authorization modules being set globally for the entire server instead of a single application, were massive hindrances to adoption.
JASPIC Defines a Standard Interface
JASPIC as mentioned wasn't delivered on time, but it did finally define a standard interface and specification for the kind of authentication mechanisms that the Servlet spec introduced all these years ago. This too resulted in an extra section in the Servlet spec, although one that was just a wee bit to conservatively worded:
"To facilitate portable implementation and integration of additional container authentication mechanisms, it is recommended that all Servlet containers implement the Servlet Container Profile of The Java™️ Authentication SPI for Containers (i.e., JSR 196)".
For something that standardises what Servlet containers basically already do, merely saying "recommended" instead of the much stronger "must", probably had been one of the major causes of the initial slow adoption of JASPIC, though at the time of writing all current Servlet containers including Tomcat and Jetty do in fact support JASPIC.
Some Issues with JASPIC
There were unfortunately other problems with JASPIC, such as the omission of a simple way to register just an authentication module (called ServerAuthModule, or SAM) by an application in a standard way. Instead, vendors were supposed to offer such functionality in a proprietary way. For instance, Payara allows for this by editing domain.xml or using the asadmin or admin console. Another issue was that JASPIC defined a very abstract interface, theoretically usable for authenticating many different types of protocols (remote EJB, HTTP/Servlet, JMS, HTTP/SOAP, etc). When used just for Servlets, this meant downcasting of several types was needed, further obscuring the experience. On top of all this, arguably the biggest problem was a very lacking TCK, which meant many servers passing certification would be barely usable in practice since literally nothing worked correctly. It would take until the end of 2016 for servers to support a reasonable amount of functionality well enough to be actually usable.
Java EE Security API Efforts Begin in 2014
In parallel with vendors improving on their JASPIC implementations, a new effort had started at the end of 2014; the Java EE Security API (JSR 375). This effort was the result of prior discussions to introduce easy of use facilities in JASPIC such as CDI support, an easy way to register just a SAM, and an HTTP specific SAM variant. Eventually it was decided to let JASPIC be the small and universal SPI (Service Provider Interface) that it had been before, and move all the higher level easy of use functionality to this new spec.
Java EE Security 1.0 primarily introduced an authentication mechanism that's HTTP specific, called HttpAuthenticationMechanism. It builds directly on the JASPIC ServerAuthModule and therefor inherits all of its behaviour and specification, with the main difference being that it's being defined as an easy to use CDI bean, with various annotations able to add higher level services.
The SAM's effective interface (merging in the methods from its parent interface) is shown below:
The HttpAuthenticationMechanism, based on the above is:
Note that the JASPIC version doesn't have any references to concrete protocol types like HtppServletRequest. Also notice how JASPIC uses the term "message" is a lot, e.g. in MessagePolicy. This is mainly in reference to SOAP, which was at the height of its hype when JASPIC was being worked on, and seems to have influenced it quite a bit. In SOAP specifically, Message Layer Security (MLS) is used to secure (sign and/or encrypt) individual SOAP messages as opposed to Transport Layer Security (TLS) which transparently encrypts the channel used for transport. In HTTP the terms "request" and "response" are more common, so "message" not rarely comes across as somewhat puzzling in this context.
Where JASPIC is just a set of interfaces, EE Security also introduces concrete authentication mechanisms build on its own HttpAuthenticationMechanism, namely BASIC and FORM that mimic their Servlet variants, as well as a new FORM based one that allows programmatic continuation of the security dialog (Servlet FORM uses a post to j_security_check as a trigger for that).
Java EE Security 1.0 also standardises the identity store via a type aptly called IdentityStore. This is a kind of database containing users and their credentials, and optionally groups. JASPIC provides some provisions for this, via the so-called Bridge Profile that allows delegation to a JAAS LoginModule, and via its PasswordValidationCallback that delegates to whatever proprietary identity store a server has activated. For Payara this would for example be its native LoginModule/Realm combination.
The former (the Bridge Profile) however is still not very easy to setup, while the latter (the callback) is restricted to password based identity stores only. The EE Security IdentityStore does not build on the existing LoginModule, but is instead a CDI bean with an interface that is more tailored to Java EE. LoginModules work by putting Principals into a Subject, with which they have been initialised earlier. Those Principals then have to be split into the user/caller principal, and the group principals. A LoginModule is also necessarily stateful because of this (it has to remember the Subject being passed in). An IdentityStore is essentially stateless, though by virtue of CDI it can have a scope. Furthermore it directly matches the EE concept of caller principal and groups.
For completeness, the two interfaces are contrasted below:
CredentialValidationResult being returned by the validate(Credential credential) method has getCallerPrincipal() and getCallerGroups() methods which unambiguously return the caller principal and optionally any groups that caller is in.
Just like with the authentication mechanisms, EE Security doesn't only provide the interfaces such as JASPIC does, but introduces concrete implementations of these as well; a database based one, and an LDAP based one.
The diagram below shows the relations in graphical form. Note that in order to keep the diagram and text somewhat manageable we left out the pluggable aspect of JACC, and the URL permission checking that Servlet does. Other containers using security, such as EJB and JCA, were left out as well. The diagram uses Payara as an example. Other EE implementations might do several things somewhat differently.
So in summary, what is the relation between EE Security and JASPIC, JACC and LoginModules/Realms?
JASPIC and JACC are both low level SPIs sitting in between (mainly) Servlet's declarative security and the Java EE Container. JASPIC does the authentication bits, JACC the authorization ones. They are both low level SPIs and not targeted at regular application developers. EE Security makes use of those lower level SPIs to provide a higher level API that -is- targeted at regular application developers.
LoginModules/Realms on their turn are the Payara specific alternative for the identity stores that EE security finally standardised.