Quantcast
Channel: Arjan Tijms' Weblog
Viewing all 66 articles
Browse latest View live

How Java EE translates web.xml constraints to Permission instances

$
0
0
It's a well known fact that in Java EE security one can specify security constraints in web.xml. It's perhaps a little lesser known fact that in full profile Java EE servers those constraints are translated by the container to instances of the Permission class. The specifications responsible for this are Servlet and JACC. This article shows a simple example of what this translation looks like.

Web.xml constraints

We're putting the following constraints in web.xml:


<security-constraint>
<web-resource-collection>
<web-resource-name>Forbidden Pattern</web-resource-name>
<url-pattern>/forbidden/*</url-pattern>
</web-resource-collection>
<auth-constraint/>
</security-constraint>

<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Pattern</web-resource-name>
<url-pattern>/protected/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>architect</role-name>
<role-name>administrator</role-name>
</auth-constraint>
</security-constraint>

<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Exact</web-resource-name>
<url-pattern>/adminservlet</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>administrator</role-name>
</auth-constraint>
</security-constraint>

<security-role>
<role-name>architect</role-name>
</security-role>
<security-role>
<role-name>administrator</role-name>
</security-role>

Java Permissions

Given the above shown constraints in web.xml the following WebResourcePermission instances will be generated, in 3 collections as shown below. For brevity only WebResourcePermission is shown. The other types are omitted.

Excluded

  • WebResourcePermission "/forbidden/*"

Unchecked

  • WebResourcePermission "/:/adminservlet:/protected/*:/forbidden/*"

Per Role

  • architect
    • WebResourcePermission "/protected/*"
  • administrator
    • WebResourcePermission "/protected/*"
    • WebResourcePermission "/adminservlet"

Below is very short explanation for the different permission types normally used for the translation. The interested reader is suggested to study the Javadoc of each type for more detailed information.


Java EE will generate 3 types of Permission instances when translating constraints expressed in web.xml; WebRoleRefPermission, WebUserDataPermission and WebResourcePermission.

WebRoleRefPermission

A web role ref permission is about mapping Servlet local roles to application roles. Especially with MVC frameworks like JSF and the upcoming JAX-RS based MVC 1.0 the use for this is perhaps questionable, as there's only one Servlet in that case that serves many different views.

WebUserDataPermission

A web user data permission is about the transport level guarantees for accessing resources (practically this almost always means HTTP vs HTTPS). This can be specified using the <user-data-constraint> element in web.xml, which we have omitted here.

WebResourcePermission

The web resource permission is about the actual access to a resource. This can be specified using the <web-resource-collection> element in web.xml, which we have used in the example above.

So let's take a look at what's going on here.

Our first web.xml constraint shown above defined so-called "excluded access", which means that nobody can access the resources defined by that pattern. In XML this is accomplished by simply omitting the auth-constraint element. This was translated to Java code by means of putting a WebResourcePermission with the pattern "/forbidden/*" in the "Excluded" collection. Although there are some differences, this is a reasonably direct translation from the XML form.

The permission shown above for the "Unchecked" collection concerns the so-called "unchecked access", which means that everyone can access those resources. This one wasn't explicitly defined in XML, although XML does have syntax for explicitly defining unchecked access. The permission shown here concerns the Servlet default mapping (a fallback for everything that doesn't match any other declared Servlet pattern).

The pattern used here may need some further explanation. In the pattern the colon (:) is a separator of a list of patterns. The first pattern is the one we grant access to, while the rest of the patterns are the exceptions to that. So unchecked access for "/:/adminservlet:/protected/*:/forbidden/*" means access to everything (e.g. /foo/readme.text) is granted to everyone, with the exception of "/adminservlet" and paths that starts with either "/protected" or "/forbidden". In this case the translation from the XML form to Java is not as direct.

The next two constraints that we showed in web.xml concerned "role-based access", which means that only callers who are in the associated roles can access resources defined by those patterns. In XML this is accomplished by putting one or more patterns together with one or more roles in a security constraint. This is translated to Java by generating {role, permission} pairs for each unique combination that appears in the XML file. It's typically most convenient then to put these entries in a map, with role the key and permission the value, as was done above, but this is not strictly necessary. Here we see that the translation doesn't directly reflect the XML structure, but the link to the XML version can surely be seen in the translation.

Obtaining the generated Permissions

There is unfortunately no API available in Java EE to directly obtain the generated Permission instances. Instead, one has to install a JACC provider that is called by the container for each individual Permission that is generated. A ready to use provider was given in a previous article, but as we saw before they are not entirely trivial to install.

Conclusion

We've shown a few simple web.xml based security constraints and saw how they translated to Java Permission instances.

There are quite a few things that we did not look at, like the option to specify one or more HTTP Methods (GET, POST, etc) with or without the deny uncovered methods feature, the option to specify a transport level guarantee, the "any authenticated user" role, combinations of overlapping patterns with different constraints, etc etc. This was done intentionally to keep the example simple and to focus on the main concept of translation without going in to too many details. In a future article we may take a look at some more advanced cases.

Arjan Tijms


Testing JASPIC 1.1 on IBM Liberty EE 7 beta

$
0
0
In this article we take a look at the latest April 2015 beta version of IBM's Liberty server, and specifically look at how well it implements the Java EE authentication standard JASPIC.

The initial version of Liberty implemented only a seemingly random assortment of Java EE APIs, but the second version that we looked at last year officially implemented the (Java EE 6) web profile. This year however the third incarnation is well on target to implement the full profile of Java EE 7.

This means IBM's newer and much lighter Liberty (abbreviated WLP), will be a true alternative for the older and incredibly obese WebSphere (abbreviated WAS) where it purely concerns the Java EE standard APIs. From having by far the most heavyweight server on the market (weighing in at well over 2GB), IBM can now offer a server that's as light and small as various offerings from its competition.

For this article we'll be specifically looking at how well JASPIC works on Liberty. Please take into account that the EE 7 version of Liberty is still a beta, so this only concerns an early look. Bugs and missing functionality are basically expected.

We started by downloading Liberty from the beta download page. The download page initially looked a little confusing, but it's constantly improving and by the time that this article was written it was already a lot clearer. Just like the GlassFish download page, IBM now offers a very straightforward Java EE Web profile download and a Java EE full profile one.

For old time WebSphere users who were used to installers that were themselves 200GB in size and only run on specific operating systems, and then happily downloaded 2GB of data that represented the actual server, it beggars belief that Liberty is now just an archive that you unzip. While the last release of Liberty already greatly improved matters by having an executable jar as download, effectively a self-extracting archive, nothing beats the ultimate simplicity of an "install" that solely consists of an archive that you unzip. This represents the pure zen of installing, shaving every non-essential component off it and leaving just the bare essentials. GlassFish has an unzip install, JBoss has it, TomEE and Tomcat has it, even the JDK has it these days, and now finally IBM has one too :)

We downloaded the Java EE 7 archive, wlp-beta-javaee7-2015.4.0.0.zip, weighing in at a very reasonable 100MB, which is about the same size as the latest beta of JBoss (WildFly 9.0 beta2). Like last year there is no required registration or anything. A license has to be accepted (just like e.g. the JDK), but that's it. The experience up to this point is as perfect as can be.

A small disappointment is that the download page lists a weird extra step that supposedly needs to be performed. It says something called a "server" needs to be created after the unzip, but luckily it appeared this is not the case. After unzipping Liberty can be started directly on OS X by pointing Eclipse to the directory where Liberty was extracted, or by typing the command "./server start" from the "./bin" directory where Liberty was extracted. Why this unnecessary step is listed is not clear. Hopefully it's just a remainder of some early alpha version. On Linux (we tried Ubuntu 14.10) there's an extra bug. The file permissions of the unzipped archive are wrong, and a "chmod +x ./bin/server" is needed to get Liberty to start using either Eclipse or the commandline.

(UPDATE: IBM responded right away by removing the redundant step mentioned by the download page)

A bigger disappointment is that the Java EE full profile archive is by default configured to only be a JSP/Servlet container. Java EE 7 has to be "activated" by manually editing a vendor specific XML file called "server.xml" and finding out that in its "featureManager" section one needs to type <feature>javaee-7.0</feature>. For some reason or the other this doesn't include JASPIC and JACC. Even though they really are part of Java EE (7), they have to be activated separately. In the case of JASPIC this means adding the following as well: <feature>jaspic-1.1</feature>. Hopefully these two issues are just packaging errors and will be resolved in the next beta or at least in the final version.

On to trying out JASPIC, we unfortunately learned that by default JASPIC doesn't really work as it should. Liberty inherited a spec compliance issue from WebSphere 8.x where the runtime insists that usernames and groups that an auth module wishes to set as the authenticated identity also exist in an IBM specific server internal identity store that IBM calls "user registry". This is however not the intend of JASPIC, and existing JASPIC modules will not take this somewhat strange requirement into account which means they will therefor not work on WebSphere and now Liberty. We'll be looking at a hack to work around this below.

Another issue is that Liberty still mandates so called group to role mapping, even when such mapping is not needed. Unlike some other servers that also mandate this by default there's currently no option to switch this requirement off, but there's an open issue for this in IBM's tracker. Another problem is that the group to role mapping file can only be supplied by the application when using an EAR archive. With lighter weight applications a war archive is often the initial choice, but when security is needed and you don't want or can't pollute the server itself with (meaningless) application specific data, then the current beta of Liberty forces the EAR archive upon you. Here too however there's already an issue filed to remedy this.

One way to work around the spec compliance issue mentioned above is by implementing a custom user registry that effectively does nothing. IBM has some documentation on how to do this, but unfortunately it's not giving exact instructions but merely outlines the process. The structure is also not entirely logical.

For instance, step 1 says "Implement the custom user registry (FileRegistrysample.java)". But in what kind of project? Where should the dependencies come from? Then step 2 says: "Creating an OSGi bundle with Bundle Activation. [...] Import the FileRegistrysample.java file". Why not create the bundle project right away and then create the mentioned file inside that bundle project? Step 4 says "Register the services", but gives no information on how to do this. Which services are we even talking about, and should they be put in an XML file or so and if so which one and what syntax? Step 3.4 asks to install the feature into Liberty using Eclipse (this works very nicely), but then step 4 and 5 are totally redundant, since they explain another more manually method to install the feature.

Even though it's outdated, IBM's general documentation on how to create a Liberty feature is much clearer. With those two articles side by side and cross checking it with the source code of the example used in the first article, I was able to build a working NOOP user registry. I had to Google for the example's source code though as the link in the article resulted in a 404. A good thing to realize is that the .esa file that's contained in the example .jar is also an archive that once unzipped contains the actual source code. Probably a trivial bit of knowledge for OSGi users, but myself being an OSGi n00b completely overlooked this and spent quite some time looking for the .java files.

The source code of the actual user registry is as follows:


package noopregistrybundle;

import static java.util.Collections.emptyList;

import java.rmi.RemoteException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;

import com.ibm.websphere.security.CertificateMapFailedException;
import com.ibm.websphere.security.CertificateMapNotSupportedException;
import com.ibm.websphere.security.CustomRegistryException;
import com.ibm.websphere.security.EntryNotFoundException;
import com.ibm.websphere.security.NotImplementedException;
import com.ibm.websphere.security.PasswordCheckFailedException;
import com.ibm.websphere.security.Result;
import com.ibm.websphere.security.UserRegistry;
import com.ibm.websphere.security.cred.WSCredential;

public class NoopUserRegistry implements UserRegistry {

@Override
public void initialize(Properties props) throws CustomRegistryException, RemoteException {
}

@Override
public String checkPassword(String userSecurityName, String password) throws PasswordCheckFailedException, CustomRegistryException, RemoteException {
return userSecurityName;
}

@Override
public String mapCertificate(X509Certificate[] certs) throws CertificateMapNotSupportedException, CertificateMapFailedException, CustomRegistryException, RemoteException {
try {
for (X509Certificate cert : certs) {
for (Rdn rdn : new LdapName(cert.getSubjectX500Principal().getName()).getRdns()) {
if (rdn.getType().equalsIgnoreCase("CN")) {
return rdn.getValue().toString();
}
}
}
} catch (InvalidNameException e) {
}

throw new CertificateMapFailedException("No valid CN in any certificate");
}

@Override
public String getRealm() throws CustomRegistryException, RemoteException {
return "customRealm"; // documentation says can be null, but should really be non-null!
}

@Override
public Result getUsers(String pattern, int limit) throws CustomRegistryException, RemoteException {
return emptyResult();
}

@Override
public String getUserDisplayName(String userSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException {
return userSecurityName;
}

@Override
public String getUniqueUserId(String userSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException {
return userSecurityName;
}

@Override
public String getUserSecurityName(String uniqueUserId) throws EntryNotFoundException, CustomRegistryException, RemoteException {
return uniqueUserId;
}

@Override
public boolean isValidUser(String userSecurityName) throws CustomRegistryException, RemoteException {
return true;
}

@Override
public Result getGroups(String pattern, int limit) throws CustomRegistryException, RemoteException {
return emptyResult();
}

@Override
public String getGroupDisplayName(String groupSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException {
return groupSecurityName;
}

@Override
public String getUniqueGroupId(String groupSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException {
return groupSecurityName;
}

@Override
public List<String> getUniqueGroupIds(String uniqueUserId) throws EntryNotFoundException, CustomRegistryException, RemoteException {
return new ArrayList<>(); // Apparently needs to be mutable
}

@Override
public String getGroupSecurityName(String uniqueGroupId) throws EntryNotFoundException, CustomRegistryException, RemoteException {
return uniqueGroupId;
}

@Override
public boolean isValidGroup(String groupSecurityName) throws CustomRegistryException, RemoteException {
return true;
}

@Override
public List<String> getGroupsForUser(String groupSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException {
return emptyList();
}

@Override
public Result getUsersForGroup(String paramString, int paramInt) throws NotImplementedException, EntryNotFoundException, CustomRegistryException, RemoteException {
return emptyResult();
}

@Override
public WSCredential createCredential(String userSecurityName) throws NotImplementedException, EntryNotFoundException, CustomRegistryException, RemoteException {
return null;
}

private Result emptyResult() {
Result result = new Result();
result.setList(emptyList());
return result;
}
}

There were two small caveats here. The first is that the documentation for getRealm says it may return null and that "customRealm" will be used as the default then. But when you actually return null authentication will fail with many null pointer exceptions appearing in the log. The second is that getUniqueGroupIds() has to return a mutable collection. If Collections#emptyList is returned it will throw an exception that no element can be inserted. Likely IBM merges the list of groups this method returns with those that are being provided by the JASPIC auth module, and directly uses this collection for that merging.

The Activator class that's mentioned in the article referenced above looks as follows:


package noopregistrybundle;

import static org.osgi.framework.Constants.SERVICE_PID;

import java.util.Dictionary;
import java.util.Hashtable;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;

import com.ibm.websphere.security.UserRegistry;

public class Activator extends NoopUserRegistry implements BundleActivator, ManagedService {

private static final String CONFIG_PID = "noopUserRegistry";

private ServiceRegistration<ManagedService> managedServiceRegistration;
private ServiceRegistration<UserRegistry> userRegistryRegistration;

@SuppressWarnings({ "rawtypes", "unchecked" })
Hashtable getDefaults() {
Hashtable defaults = new Hashtable();
defaults.put(SERVICE_PID, CONFIG_PID);
return defaults;
}

@SuppressWarnings("unchecked")
public void start(BundleContext context) throws Exception {
managedServiceRegistration = context.registerService(ManagedService.class, this, getDefaults());
userRegistryRegistration = context.registerService(UserRegistry.class, this, getDefaults());
}

@Override
public void updated(Dictionary<String, ?> properties) throws ConfigurationException {

}

public void stop(BundleContext context) throws Exception {
if (managedServiceRegistration != null) {
managedServiceRegistration.unregister();
managedServiceRegistration = null;
}
if (userRegistryRegistration != null) {
userRegistryRegistration.unregister();
userRegistryRegistration = null;
}
}
}

Here we learned what that cryptic "Register the services" instruction from the article meant; it are the two calls to context.registerService here. Surely something that's easy to guess, or isn't it?

Finally a MANIFEST.FM file had to be created. The Eclipse tooling should normally help here, but it our case it worked badly. The "Analyze code and add dependencies to the MANIFEST.MF" command in the manifest editor (under the Dependencies tab) didn't work at all, and "org.osgi.service.cm" couldn't be chosen from the Imported Packages -> Add dialog. Since this import is actually used (and OSGi requires you to list each and every import used by your code) I added this manually. The completed file looks as follows:


Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: NoopRegistryBundle
Bundle-SymbolicName: NoopRegistryBundle
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: noopregistrybundle.Activator
Import-Package: com.ibm.websphere.security;version="1.1.0",
javax.naming,
javax.naming.ldap,
org.osgi.service.cm,
org.osgi.framework
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Export-Package: noopregistrybundle

Creating yet another project for the so-called feature, importing this OSGi bundle there and installing the build feature into Liberty was all pretty straightforward when following the above mentioned articles.

The final step consisted of adding the noop user registry to Liberty's server.xml, which looked as follows:


<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">

<featureManager>
<feature>javaee-7.0</feature>
<feature>jaspic-1.1</feature>
<feature>localConnector-1.0</feature>
<feature>usr:NoopRegistryFeature</feature>
</featureManager>

<httpEndpoint httpPort="9080" httpsPort="9443" id="defaultHttpEndpoint"/>

<noopUserRegistry/>
</server>

With this in place, JASPIC indeed worked on Liberty, which is absolutely great! To do some more thorough testing of how compatible Liberty exactly is we used the JASPIC tests that I contributed to the Java EE 7 samples project. These tests have been used by various other server vendors already and give a basic impression of what things work and do not work.

The tests had to be adjusted for Liberty because of its requirement to add an EAR wrapper that hosts the mandated group to role mapping.

After running the tests, the following failures were reported:

TestClassComment
testPublicPageNotRememberLogin org.javaee7.jaspic.basicauthentication.BasicAuthenticationPublicTest
testPublicPageLoggedin org.javaee7.jaspic.basicauthentication.BasicAuthenticationPublicTest
testProtectedAccessIsStateless org.javaee7.jaspic.basicauthentication.BasicAuthenticationStatelessTest
testPublicServletWithLoginCallingEJB org.javaee7.jaspic.ejbpropagation.ProtectedEJBPropagationTest
testProtectedServletWithLoginCallingEJB org.javaee7.jaspic.ejbpropagation.PublicEJBPropagationLogoutTest
testProtectedServletWithLoginCallingEJB org.javaee7.jaspic.ejbpropagation.PublicEJBPropagationTest
testLogout org.javaee7.jaspic.lifecycle.AuthModuleMethodInvocationTestSAM method cleanSubject not called, but should have been
testJoinSessionIsOptional org.javaee7.jaspic.registersession.RegisterSessionTest
testRemembersSession org.javaee7.jaspic.registersession.RegisterSessionTest
testResponseWrapping org.javaee7.jaspic.wrapping.WrappingTest Response wrapped by SAM did not arrive in Servlet
testRequestWrapping org.javaee7.jaspic.wrapping.WrappingTest Request wrapped by SAM did not arrive in Servlet

Specifically the EJB, "logout calls cleanSubject"& register session (both new JASPIC 1.1 features) and request/response wrapper tests failed.

Two of those are new JASPIC 1.1 features and likely IBM just hasn't implemented those yet for the beta. Request/response wrapper failures is a known problem from JASPIC 1.0 times. Although most servers implement it now curiously not a single JASPIC implementation did so back in the Java EE 6 time frame (even though it was a required feature by the spec).

First Java EE 7 production ready server?

At the time of writing, which is 694 days (1 year, ~10 months) after the Java EE 7 spec was finalized, there are 3 certified Java EE servers but none of them is deemed by their vendor as "production ready". With the implementation cycle of Java EE 6 we saw that IBM was the first vendor to release a production ready server after 559 days (1 year, 6 months), with Oracle following suit at 721 days (1 year, 11 months).

Oracle (perhaps unfortunately) doesn't do public beta releases and is a little tight lipped about their up coming Java EE 7 WebLogic 12.2.1 release, but it's not difficult to guess that they are working hard on it (I have it on good authority that they indeed are). Meanwhile IBM has just released a beta that starts to look very complete. Looking at the amount of time it took both vendors last time around it might be a tight race between the two for releasing the first production ready Java EE 7 server. Although JBoss' WildFly 8.x is certified, a production ready and supported release is likely still at least a full year ahead when looking at the current state of the WildFly branch and if history is anything to go by (it took JBoss 923 days (2 years, 6 months) last time).

Conclusion

Despite a few bugs in the packaging of the full and web profile servers, IBM's latest beta shows incredible promise. The continued effort in making its application server yet again simpler to install for developers is nothing but applaudable. IBM clearly meant it when they started the Liberty project a few years ago and told their mission was to optimize the developer experience.

There are a few small bugs and one somewhat larger violation in its JASPIC implementation, but we have to realize it's just a beta. In fact, IBM engineers are already looking at the JASPIC issues.

To summarize the good and not so good points:

Good

  • Runs on all operating systems (no special IBM JDK required)
  • Monthly betas of EE 7 server
  • Liberty to support Java EE 7 full profile
  • Possibly on its way to become the first production ready EE 7 server
  • Public download page without required registration
  • Very good file size for full profile (100MB)
  • Extremely easy "download - unzip - ./server start" experience

Not (yet) so good

  • Download page lists totally unnecessary step asking to "create a server" (update: now fixed by IBM)
  • Wrong file permissions in archive for usage on Linux; executable attribute missing on bin/server
  • Wrong configuration of server.xml; both web and full profile by default configured as JSP/Servlet only
  • "javaee-7.0" feature in server.xml doesn't imply JASPIC and JACC, while both are part of Java EE
  • JASPIC runtime tries to validate usernames/groups in internal identity store (violation of JASPIC spec)
  • Mandatory group to role mapping, even when this is not needed
  • Mandatory usage of EAR archive when group to role mapping has to be provided by the application
  • Not all JASPIC features implemented yet (but remember that we looked at a beta version)

Arjan Tijms

OmniFaces 2.1-RC1 has been released!

$
0
0
We are proud to announce that OmniFaces 2.1 release candidate 1 has been made available for testing.

OmniFaces 2.1 is the second release that will depend on JSF 2.2 and CDI 1.1 from Java EE 7. Since Java EE 7 availability remains somewhat scarce, we maintain a no-frills 1.x branch for JSF 2.0 (without CDI). For this branch we've simultaneously released a release candidate as well: 1.11-RC1.

A full list of what's new and changed is available here.

OmniFaces 2.1 RC1 can be tested by adding the following dependency to your pom.xml:


<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces</artifactId>
<version>2.1-RC1</version>
</dependency>

Alternatively the jars files can be downloaded directly.

For the 1.x branch the coordinates are:


<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces</artifactId>
<version>1.11-RC1</version>
</dependency>
This one too can be downloaded directly.

If no major bugs surface we hope to release OmniFaces 2.1 final soon.

Arjan Tijms

NEC's WebOTX - a commercial GlassFish derivative

$
0
0
In a previous article we took a look at an obscure Java EE application server that's only known in Korea and virtually unknown everywhere else. Korea is not the only country that has a national application server though. Japan is the other country. In fact, it has not one, but three obscure application servers.

These Japanese servers, the so-called obscure 3, are so unknown outside of Japan that major news events like a Java EE 7 certification simply just does not make it out here.

Those servers are the following:

  1. NEC WebOTX
  2. Hitachi Application Server
  3. Fujitsu Interstage AS

In this article we're going to take a quick look at the first one of this list: NEC WebOTX.

While NEC does have an international English page where a trial can be downloaded it only contains a very old version of WebOTX; 8.4, which implements Java EE 5. This file is called otx84_win32bitE.exe and is about 92MB in size.

As with pretty much all of the Asian application servers, the native language pages contain much more and much newer versions. In this case the Japanese page contains a recent version of WebOTX; 9.2, which implements Java EE 6. This file is called OTXEXP92.exe and is about 111MB in size. A bit of research revealed that a OTXEXP91.exe also once existed, but no other versions were found.

The file is a Windows installer, that presents several dialogs in Japanese. If you can't read Japanese it's a bit difficult to follow. Luckily, there are English instructions for the older WebOTX 8.4 available that still apply to the WebOTX 9.2 installer process as well. Installation takes a while and several scripts seem to start running, and it even wants to reboot the computer (a far cry from download & unzip, start server), but after a while WebOTX was installed in e:\webotx.

Jar and file comparison

One of the first things I often do after installing a new server is browse a little through the folders of the installation. This gives me some general idea about how the server is structured, and quite often will reveal what implementation components a particular server is using.

Surprisingly, the folder structure somewhat resembled that of GlassFish, but with some extra directories. E.g.

GlassFish 3.1.2.2 main dirWebOTX 9.2 main dir

 

Looking at the modules directory in fact did make it clear that WebOTX is in fact strongly based on GlassFish:

GlassFish 3.1.2.2 modules dirWebOTX 9.2 modules dir

 

The jar files are largely identical in the part shown, although WebOTX does have the extra jar here and there. It's a somewhat different story when it comes to the glassfish-* and gf-* jars. None of these are present in WebOTX, although for many similar ones are present but just prefixed by webotx- as shown below:

glassfish- prefixed jarswebotx- prefixed jars

 

When actually looking inside one of the jars with a matching name except for the prefix e.g. glassfish.jar vs webotx.jar, then it becomes clear that at least the file names are largely the same again, except for the package being renamed. See below:

glassfish.jarwebotx.jar

 

Curiously a few jars with similar names have internally renamed package names. This is for instance the case for the well known Jersey (JAX-RS) jar, but for some reason not for Mojarra (JSF). See below:

glassfish jersey-core.jarwebotx jersey-core.jar

 

Besides the differences shown above, name changes occur at a number of other places. For instance well known GlassFish environment variables have been renamed to corresponding WebOTX ones, and pom.xml as well as MANIFEST.FM files in jar files have some renamed elements as well. For instance, the embedded pom.xml for the mojarra jar contains this:


<project>
<modelVersion>4.0.0</modelVersion>
<!-- upds start 20121122 org.glassfish to com.nec.webotx.as -->
<groupId>com.nec.webotx.as</groupId>
<!-- upds end 20121122 org.glassfish to com.nec.webotx.as -->
<artifactId>javax.faces</artifactId>
<version>9.2.1</version>
<packaging>jar</packaging>
<name>
Oracle's implementation of the JSF 2.1 specification.
</name>
<description>
This is the master POM file for Oracle's Implementation of the JSF 2.1 Specification.
</description>
With the MANIFEST.FM containing this:

Implementation-Title: Mojarra
Implementation-Version: 9.2.1
Tool: Bnd-0.0.249
DSTAMP: 20131217
TODAY: December 17 2013
Bundle-Name: Mojarra JSF Implementation 9.2.1 (20131217-1350) https://
swf0200036.swf.nec.co.jp/app/svn/WebOTX-SWFactory/dev/mojarra/branche
s/mojarra2.1.26@96979
TSTAMP: 1350
DocName: Mojarra Implementation Javadoc
Implementation-Vendor: Oracle America, Inc.

 

Trying out the server

Rather peculiar to say the least for a workstation is that WebOTX is automatically started when the computer is rebooted. Unlike most other Java EE servers the default HTTP port after installation is 80. There's no default application installed and requesting http://localhost results in the following screen:

The admin interface is present on port 5858. For some reason the initial login screen asks for very specific browser versions though:

After logging in with username "admin", password "adminadmin", we're presented with a colorful admin console:

As is not rarely the case with admin consoles for Java EE servers there's a lot of ancient J2EE stuff there. Options for generating stubs for EJB CMP beans are happily being shown to the user. In a way this is not so strange. Modern Java EE doesn't mandate a whole lot of things to be configured via a console, thanks to the ongoing standardization and simplification efforts, so what's left is not rarely old J2EE stuff.

I tried to upload a .war file of the OmniFaces showcase, but unfortunately this part of the admin console was still really stuck in ancient J2EE times as it politely told me it only accepted .ear files:

After zipping the .war file into a second zip file and then renaming it to .ear (a rather senseless exercise), the result was accepted and after requesting http://localhost again the OmniFaces showcase home screen was displayed:

As we can see, it's powered by Mojarra 9.2.1. Now we all know that Mojarra moves at an amazing pace, but last time I looked it was still at 2.3 m2. Either NEC travelled some time into the future and got its Mojarra version there, or the renaming in MANIFEST.FM as shown above was a little bit too eagerly done ;)

At any length, all of the functionality in the showcase seemed to work, but as it was tested on GlassFish 3 before this wasn't really surprising.

Conclusion

We took a short look at NEC's WebOTX and discovered it's a GlassFish derivative. This is perhaps a rather interesting thing. Since Oracle stopped commercial support for GlassFish a while ago, many wondered if the code base wouldn't wither at least a little when potentially fewer people would use it in production. However, if a large and well known company such as NEC offers a commercial offering based on GlassFish then this means that next to Payara there remains more interest in the GlassFish code beyond being "merely" an example for other vendors.

While we mainly looked at the similarities with respect to the jar files in the installed product we didn't look at what value NEC exactly added to GlassFish. From a very quick glance it seems that at least some of it is related to management and monitoring, but to be really sure a more in depth study would be needed.

It remains remarkable though that while the company NEC is well known outside Japan for many products, it has its own certified Java EE server that's virtually unheard of outside of Japan.

Arjan Tijms

OmniFaces 2.1 released!

$
0
0
We're proud to announce that today we've released OmniFaces 2.1. OmniFaces is a utility library for JSF that provides a lot of utilities to make working with JSF much easier.

OmniFaces 2.1 is the second release that will depend on JSF 2.2 and CDI 1.1 from Java EE 7. Since Java EE 7 availability remains somewhat scarce, we maintain a no-frills 1.x branch for JSF 2.0 (without CDI) as well.

The easiest way to use OmniFaces 2.1 is via Maven by adding the following to pom.xml:


<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces</artifactId>
<version>2.1</version>
</dependency>

Alternatively the jars files can be downloaded directly.

A complete overview of all that's new can be found on the what's new page, and some more details can be found in BalusC's blogpost about this release.

As usual the release contains an assortment of new features, some changes and a bunch of fixes. One particular fix that took some time to get right is getting a CDI availability check to work correctly with Tomcat + OpenWebBeans (OWB). After a long discussion we finally got this to work, with special thanks to Mark Struberg and Ludovic Pénet.

One point worth noting is that since we joined the JSF EG, our time has to be shared between that and working on OmniFaces. In addition some code that's now in OmniFaces might move to JSF core (such as already happened for the IterableDataModel in order to support the Iterable interface in UIData and UIRepeat). For the OmniFaces 2.x line this will have no effect though, but for OmniFaces 3.x (which will focus on JSF 2.3) it may.

We will start planning soon for OmniFaces 2.2. Feature requests are always welcome ;)

Arjan Tijms

JSF 2.3 new feature: registrable DataModels

$
0
0
Iterating components in JSF such as h:dataTable and ui:repeat have the DataModel class as their native input type. Other datatypes such as List are supported, but these are handled by build-in wrappers; e.g. an application provided List is wrapped into a ListDataModel.

While JSF has steadily expanded the number of build-in wrappers and JSF 2.3 has provided new ones for Map and Iterable, a long standing request is for users (or libraries) to be able to register their own wrappers.

JSF 2.3 will now (finally) let users do this. The way this is done is by creating a wrapper DataModel for a specific type, just as one may have done years ago when returning data from a backing bean, and then annotating it with the new @FacesDataModel annotation. A “forClass” attribute has to be specified on this annotation that designates the type this wrapper is able to handle.

The following gives an abbreviated example of this:


@FacesDataModel(forClass = MyCollection.class)
public class MyCollectionModel<E> extends DataModel<E> {

@Override
public E getRowData() {
// access MyCollection here
}

@Override
public void setWrappedData(Object myCollection) {
// likely just store myCollection
}

// Other methods omitted for brevity
}

Note that there are two types involved here. The “forClass” attribute is the collection or container type that the DataModel wraps, while the generic parameter E concerns the data this collection contains. E.g. Suppose we have a MyCollection<User>, then “forClass” would correspond to MyCollection, and E would correspond to User. If set/getWrappedData was generic the “forClass” attribute may not have been needed, as generic parameters can be read from class definitions, but alas.

With a class definition as given above present, a backing bean can now return a MyCollection as in the following example:


@Named
public class MyBacking {
public MyCollection<User> getUsers() {
// return myCollection
}
}
h:dataTable will be able to work with this directly, as shown in the example below:

<h:dataTable value="#{myBacking.users}" var="user">
<h:column>#{user.name}</h:column>
</h:dataTable>

There are a few things noteworthy here.

Traditionally JSF artefacts like e.g. ViewHandlers are registered using a JSF specific mechanism, kept internally in a JSF data structure and are looked up using a JSF factory. @FacesDataModel however has none of this and instead fully delegates to CDI for all these concerns. The registration is done automatically by CDI by the simple fact that @FacesDataModel is a CDI qualifier, and lookup happens via the CDI BeanManager (although with a small catch, as explained below).

This is a new direction that JSF is going in. It has already effectively deprecated its own managed bean facility in favour of CDI named beans, but is now also favouring CDI for registration and lookup of the pluggable artefacts it supports. New artefacts will henceforth very likely exclusively use CDI for this, while some existing ones are retrofitted (like e.g. Converters and Validators). Because of the large number of artefacts involved and the subtle changes in behaviour that can occur, not all existing JSF artefacts will however change overnight to registration/lookup via CDI.

Another thing to note concerns the small catch with the CDI lookup that was mentioned above. The thing is that with a direct lookup using the BeanManager we’d get a very specific wrapper type. E.g. suppose there was no build-in wrapper for List and one was provided via @FacesDataModel. Now also suppose the actual data type encountered at runtime is an ArrayList. Clearly, a direct lookup for ArrayList will do us no good as there’s no wrapper available for exactly this type.

This problem is handled via a CDI extension that observes all definitions of @FacesDataModel that are found by CDI during startup and stores the types they handle in a collection. This is afterwards sorted such that for any 2 classes X and Y from this collection, if an object of X is an instanceof an object of Y, X appears in the collection before Y. The collection's sorting is otherwise arbitrary.

With this collection available, the logic behind @FacesDataModel scans this collection of types from beginning to end to find the first match which is assignable from the type that we encountered at runtime. Although it’s an implementation detail, the following shows an example of how the RI implements this:


getDataModelClassesMap(cdi).entrySet().stream()
.filter(e -> e.getKey().isAssignableFrom(forClass))
.findFirst()
.ifPresent(
e -> dataModel.add(
cdi.select(
e.getValue(),
new FacesDataModelAnnotationLiteral(e.getKey())
).get())
);

In effect this means we either lookup the wrapper for our exact runtime type, or the closest super type. I.e. following the example above, the wrapper for List is found and used when the runtime type is ArrayList.

Before JSF 2.3 is finalised there are a couple of things that may still change. For instance, Map and Iterable have been added earlier as build-in wrappers, but could be refactored to be based on @FacesDataModel as well. The advantage is be that the runtime would be a client of the new API as well, which on its turn means its easier for the user to comprehend and override.

A more difficult and controversial change is to allow @FacesDataModel wrappers to override build-in wrappers. Currently it’s not possible to provide one own’s List wrapper, since List is build in and takes precedence. If @FacesDataModel would take precedence, then a user or library would be able to override this. This by itself is not that bad, since JSF lives and breathes by its ability to let users or libraries override or extend core functionality. However, the fear is that via this particular way of overriding a user may update one if its libraries that happens to ship with an @FacesDataModel implementation for List, which would then take that user by surprise.

Things get even more complicated when both the new Iterable and Map would be implemented as @FacesDataModel AND @FacesDataModel would take precedence over the build-in types. In that case the Iterable wrapper would always match before the build-in List wrapper, making the latter unreachable. Now logically this would not matter as Iterable handles lists just as well, but in practice this may be a problem for applications that in some subtle way depend on the specific behaviour of a given List wrapper (in all honestly, such applications will likely fail too when switching JSF implementations).

Finally, doing totally away with the build-in wrappers and depending solely on @FacesDataModel is arguably the best option, but problematic too for reasons of backwards compatibility. This thus poses an interesting challenge between two opposite concerns: “Nothing can ever change, ever” and “Modernise to stay relevant and competitive”.

Conclusion

With @FacesDataModel custom DataModel wrappers can be registered, but those wrappers can not (yet) override any of the build-in types.

Arjan Tijms

Activating JASPIC in JBoss WildFly

$
0
0
JBoss WildFly has a rather good implementation of JASPIC, the Java EE standard API to build authentication modules.

Unfortunately there's one big hurdle for using JASPIC on JBoss WildFly; it has to be activated. This activation is somewhat of a hack itself, and is done by putting the following XML in a file called standalone.xml that resides with the installed server:


<security-domain name="jaspitest" cache-type="default">
<authentication-jaspi>
<login-module-stack name="dummy">
<login-module code="Dummy" flag="optional"/>
</login-module-stack>
<auth-module code="Dummy"/>
</authentication-jaspi>
</security-domain>

Subsequently in the application a file called WEB-INF/jboss-web.xml needs to be created that references this (dummy) domain:


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

While this works it requires the installed server to be modified. For a universal Java EE application that has to run on multiple servers this is a troublesome requirement. While not difficult, it's something that's frequently forgotten and can take weeks if not months to resolve. And when it finally is resolved the entire process of getting someone to add the above XML fragment may have to be repeated all over again when a new version of JBoss is installed.

Clearly having to activate JASPIC using a server configuration file is less than ideal. The best solution would be to not require any kind of activation at all (like is the case for e.g. GlassFish, Geronimo and WebLogic). But this is currently not implemented for JBoss WildFly.

The next best thing is doing this activation from within the application. As it appears this is indeed possible using some reflective magic and the usage of JBoss (Undertow) internal APIs. Here's where the OmniSecurity JASPIC Undertow project comes in. With this project JASPIC can be activated by putting the following in the pom.xml of a Maven project:


<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces-security-jaspic-undertow</artifactId>
<version>1.0</version>
</dependency>

The above causes JBoss WildFly/Undertow to load an extension that uses a number of internal APIs. It's not entirely clear why, but some of those are directly available, while other ones have to be declared as available. Luckily this can be done from within the application as well by creating a META-INF/jboss-deployment-structure.xml file with the following content:


<?xml version='1.0' encoding='UTF-8'?>
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
<deployment>
<dependencies>
<module name="org.wildfly.extension.undertow" services="export" export="true" />
</dependencies>
</deployment>
</jboss-deployment-structure>

So how does the extension exactly work?

The most important code consists out of two parts. A reflective part to retrieve what JBoss calls the "security domain" (the default is "other") and another part that uses the Undertow internal APIs to activate JASPIC. This is basically the same code Undertow would execute if the dummy domain is put in standalone.xml.

For completeness, the reflective part to retrieve the domain is:


String securityDomain = "other";

IdentityManager identityManager = deploymentInfo.getIdentityManager();
if (identityManager instanceof JAASIdentityManagerImpl) {
try {
Field securityDomainContextField = JAASIdentityManagerImpl.class.getDeclaredField("securityDomainContext");
securityDomainContextField.setAccessible(true);
SecurityDomainContext securityDomainContext = (SecurityDomainContext) securityDomainContextField.get(identityManager);

securityDomain = securityDomainContext.getAuthenticationManager().getSecurityDomain();

} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
logger.log(Level.SEVERE, "Can't obtain name of security domain, using 'other' now", e);
}
}

The part that uses Undertow APIs to activate JASPIC is:


ApplicationPolicy applicationPolicy = new ApplicationPolicy(securityDomain);
JASPIAuthenticationInfo authenticationInfo = new JASPIAuthenticationInfo(securityDomain);
applicationPolicy.setAuthenticationInfo(authenticationInfo);
SecurityConfiguration.addApplicationPolicy(applicationPolicy);

deploymentInfo.setJaspiAuthenticationMechanism(new JASPIAuthenticationMechanism(securityDomain, null));
deploymentInfo.setSecurityContextFactory(new JASPICSecurityContextFactory(securityDomain));
The full source can be found on GitHub.

Conclusion

For JBoss WildFly it's needed to activate JASPIC. There are two hacks available to do this. One requires a modification to standalone.xml and a jboss-web.xml, while the other requires a jar on the classpath of the application and a jboss-deployment-structure.xml file.

It would be best if such activation was not required at all. Hopefully this will indeed be the case in a future JBoss.

Arjan Tijms

How Servlet containers all implement identity stores differently

$
0
0
In Java EE security two artefacts play a major role, the authentication mechanism and the identity store.

The authentication mechanism is responsible for interacting with the caller and the environment. E.g. it causes a UI to be rendered that asks for details such as a username and password, and after a postback retrieves these from the request. As such it's roughly equivalent to a controller in the MVC architecture.

Java EE has standardised 4 authentication mechanisms for a Servlet container, as well as a JASPIC API profile to provide a custom authentication mechanism for Servlet (and one for SOAP, but let's ignore that for now). Unfortunately standard custom mechanisms are only required to be supported by a full Java EE server, which means the popular web profile and standalone servlet containers are left in the dark.

Servlet vendors can adopt the standard API if they want and the Servlet spec even encourages this, but in practice few do so developers can't depend on this. (Spec text is typically quite black and white. *Must support* means it's there, anything else like *should*, *is encouraged*, *may*, etc simply means it's not there)

The following table enumerates the standard options:

  1. Basic
  2. Digest (encouraged to be supported, not required)
  3. Client-cert
  4. Form
  5. Custom/JASPIC(encouraged for standalone/web profile Servlet containers, required for full profile Servlet containers)

The identity store on its turn is responsible for providing access to a storage system where caller data and credentials are stored. E.g. when being given a valid caller name and password as input it returns a (possibly different) caller name and zero or more groups associated with the caller. As such it's roughly equivalent to a model in the MVC architecture; the identity store knows nothing about its environment and does not interact with the caller. It only performs the {credentials in, caller data out} function.

Identity stores are somewhat shrouded in mystery, and not without reason. Java EE has not standardised any identity store, nor has it really standardised any API or interface for them. There is a bridge profile for JAAS LoginModules, which are arguably the closest thing to a standard interface, but JAAS LoginModules can not be used in a portable way in Java EE since essential elements of them are not standardised. Furthermore, this bridge profile can only be used for custom authentication mechanisms (using JASPIC), which is itself only guaranteed to be available for Servlet containers that reside within a full Java EE server as mentioned above.

What happens now is that every Servlet container provides a proprietary interface and lookup method for identity stores. Nearly all of them ship with a couple of default implementations for common storage systems that the developer can choose to use. The most common ones are listed below:

  • In-memory (properties file/xml file based)
  • Database (JDBC/DataSource based)
  • LDAP

As a direct result of not being standardised, not only do Servlet containers provide their own implementations, they also each came up with their own names. Up till now no less than 16(!) terms were discovered for essentially the same thing:

  1. authenticator
  2. authentication provider
  3. authentication repository
  4. authentication realm
  5. authentication store
  6. identity manager
  7. identity provider
  8. identity store
  9. login module
  10. login service
  11. realm
  12. relying party
  13. security policy domain
  14. security domain
  15. service provider
  16. user registry

Following a vote in the EG for the new Java EE security JSR, it was decided to use the term "identity store" going forward. This is therefor also the term used in this article.

To give an impression of how a variety of servlet containers have each implemented the identity store concept we analysed a couple of them. For each one we list the main interface one has to implement for a custom identity store, and if possible an overview of how the container actually uses this interface in an authentication mechanism.

The servlet containers and application servers containing such containers that we've looked at are given in the following list. Each one is described in greater detail below.

  1. Tomcat
  2. Jetty
  3. Undertow
  4. JBoss EAP/WildFly
  5. Resin
  6. GlassFish
  7. Liberty
  8. WebLogic

 

Tomcat

Tomcat calls its identity store "Realm". It's represented by the interface shown below:


public interface Realm {

Principal authenticate(String username);
Principal authenticate(String username, String credentials);
Principal authenticate(String username, String digest, String nonce, String nc, String cnonce, String qop, String realm, String md5a2);
Principal authenticate(GSSContext gssContext, boolean storeCreds);
Principal authenticate(X509Certificate certs[]);

void backgroundProcess();
SecurityConstraint [] findSecurityConstraints(Request request, Context context);
boolean hasResourcePermission(Request request, Response response, SecurityConstraint[] constraint, Context context) throws IOException;
boolean hasRole(Wrapper wrapper, Principal principal, String role);
boolean hasUserDataPermission(Request request, Response response, SecurityConstraint[] constraint) throws IOException;

void addPropertyChangeListener(PropertyChangeListener listener);
void removePropertyChangeListener(PropertyChangeListener listener);

Container getContainer();
void setContainer(Container container);
CredentialHandler getCredentialHandler();
void setCredentialHandler(CredentialHandler credentialHandler);
}

According to the documentation, "A Realm [identity store] is a "database" of usernames and passwords that identify valid users of a web application (or set of web applications), plus an enumeration of the list of roles associated with each valid user."

Tomcat's bare identity store interface is rather big as can be seen. In practice though implementations inherit from RealmBase, which is a base class (as its name implies). Somewhat confusingly its JavaDoc says that it's a realm "that reads an XML file to configure the valid users, passwords, and roles".

The only methods that most of Tomcat's identity stores implement are authenticate(String username, String credentials) for the actual authentication, String getName() to return the identity store's name (this would perhaps have been an annotation if this was designed today), and startInternal() to do initialisation (would likely be done via an @PostConstruct annotation today).

Example of usage

The code below shows an example of how Tomcat actually uses its identity store. The following shortened fragment is taken from the implementation of the Servlet FORM authentication mechanism in Tomcat.


// Obtain reference to identity store
Realm realm = context.getRealm();

if (characterEncoding != null) {
request.setCharacterEncoding(characterEncoding);
}
String username = request.getParameter(FORM_USERNAME);
String password = request.getParameter(FORM_PASSWORD);

// Delegating of authentication mechanism to identity store
principal = realm.authenticate(username, password);

if (principal == null) {
forwardToErrorPage(request, response, config);
return false;
}

if (session == null) {
session = request.getSessionInternal(false);
}

// Save the authenticated Principal in our session
session.setNote(FORM_PRINCIPAL_NOTE, principal);

What sets Tomcat aside from most other systems is that the authenticate() call in most cases directly goes to the custom identity store implementation instead of through many levels of wrappers, bridges, delegators and what have you. This is even true when the provided base class RealmBase is used.

 

Jetty

Jetty calls its identity store LoginService. It's represented by the interface shown below:


public interface LoginService {
String getName();
UserIdentity login(String username, Object credentials, ServletRequest request);
boolean validate(UserIdentity user);

IdentityService getIdentityService();
void setIdentityService(IdentityService service);

void logout(UserIdentity user);
}

According to its JavaDoc, a "Login service [identity store] provides an abstract mechanism for an [authentication mechanism] to check credentials and to create a UserIdentity using the set [injected] IdentityService".

There are a few things to remark here. The getName() method names the identity store. This would likely be done via an annotation had this interface been designed today.

The essential method of the Jetty identity store is login(). It's username/credentials based, where the credentials are an opaque Object. The ServletRequest is not often used, but a JAAS bridge uses it to provide a RequestParameterCallback to Jetty specific JAAS LoginModules.

validate() is essentially a kind of shortcut method for login() != null, albeit without using the credentials.

A distinguishing aspect of Jetty is that its identity stores get injected with an IdentityService, which the store has to use to create user identities (users) based on a Subject, (caller) Principal and a set of roles. It's not 100% clear what this was intended to accomplish, since the only implementation of this service just returns new DefaultUserIdentity(subject, userPrincipal, roles), where DefaultUserIdentity is mostly just a simple POJO that encapsulates those three data items.

Another remarkable method is logout(). This is remarkable since the identity store typically just returns authentication data and doesn't hold state per user. It's the authentication mechanism that knows about the environment in which this authentication data is used (e.g. knows about the HTTP request and session). Indeed, almost no identity stores make use of this. The only one that does is the special identity store that bridges to JAAS LoginModules. This one isn't stateful, but provides an operation on the passed in user identity. As it appears, the principal returned by this bridge identity store encapsulates the JAAS LoginContext, on which the logout() method is called at this point.

Example of usage

The code below shows an example of how Jetty uses its identity store. The following shortened and 'unfolded' fragment is taken from the implementation of the Servlet FORM authentication mechanism in Jetty.


if (isJSecurityCheck(uri)) {
String username = request.getParameter(__J_USERNAME);
String password = request.getParameter(__J_PASSWORD);

// Delegating of authentication mechanism to identity store
UserIdentity user = _loginService.login(username, password, request);
if (user != null) {
renewSession(request, (request instanceof Request? ((Request)request).getResponse() : null));

HttpSession session = request.getSession(true);
session.setAttribute(__J_AUTHENTICATED, new SessionAuthentication(getAuthMethod(), user, password));

// ...

base_response.sendRedirect(redirectCode, response.encodeRedirectURL(nuri));
return form_auth;
}
// ...
}

In Jetty a call to the identity store's login() method will in most cases directly call the installed identity store, and will not go through many layers of delegation, bridges, etc. There is a convenience base class that identity store implementations can use, but this is not required.

If the base class is used, two abstract methods have to be implemented; UserIdentity loadUser(String username) and void loadUsers(), where typically only the former really does something. When this base class is indeed used, the above call to login() goes to the implementation in the base class. This first checks a cache, and if the user is not there calls the sub class via the mentioned loadUser() class.


public UserIdentity login(String username, Object credentials, ServletRequest request) {

UserIdentity user = _users.get(username);

if (user == null)
user = loadUser(username);

if (user != null) {
UserPrincipal principal = (UserPrincipal) user.getUserPrincipal();
if (principal.authenticate(credentials))
return user;
}

return null;
}

The user returned from the sub class has a feature that's a little different from most other servers; it contains a Jetty specific principal that knows how to process the opaque credentials. It delegates this however to a Credential implementation as shown below:


public boolean authenticate(Object credentials) {
return credential != null && credential.check(credentials);
}

The credential used here is put into the user instance and represents the -expected- credential and can be of a multitude of types e.g. Crypt, MD5 or Password. MD5 means the expected password is MD5 hashed, while just Password means the expected password is plain text. The check for the latter looks as follows:


public boolean check(Object credentials) {
if (this == credentials)
return true;
if (credentials instanceof Password)
return credentials.equals(_pw);
if (credentials instanceof String)
return credentials.equals(_pw);
if (credentials instanceof char[])
return Arrays.equals(_pw.toCharArray(), (char[]) credentials);
if (credentials instanceof Credential)
return ((Credential) credentials).check(_pw);
return false;
}

 

Undertow

Undertow is one of the newest Servlet containers. It's created by Red Hat to replace Tomcat (JBossWeb) in JBoss EAP, and can already be used in WildFly 8/9/10 which are the unsupported precursors for JBoss EAP 7. Undertow can also be used standalone.

The native identity store interface of Undertow is the IdentityManager, which is shown below:


public interface IdentityManager {
Account verify(Credential credential);
Account verify(String id, Credential credential);
Account verify(Account account);
}
Peculiar enough there are no direct implementations for actual identity stores shipped with Undertow.

Example of usage

The code below shows an example of how Undertow actually uses its identity store. The following shortened fragment is taken from the implementation of the Servlet FORM authentication mechanism in Undertow.


FormData data = parser.parseBlocking();
FormData.FormValue jUsername = data.getFirst("j_username");
FormData.FormValue jPassword = data.getFirst("j_password");
if (jUsername == null || jPassword == null) {
return NOT_AUTHENTICATED;
}

String userName = jUsername.getValue();
String password = jPassword.getValue();
AuthenticationMechanismOutcome outcome = null;
PasswordCredential credential = new PasswordCredential(password.toCharArray());

// Obtain reference to identity store
IdentityManager identityManager = securityContext.getIdentityManager();

// Delegating of authentication mechanism to identity store
Account account = identityManager.verify(userName, credential);

if (account != null) {
securityContext.authenticationComplete(account, name, true);
outcome = AUTHENTICATED;
} else {
securityContext.authenticationFailed(MESSAGES.authenticationFailed(userName), name);
}

if (outcome == AUTHENTICATED) {
handleRedirectBack(exchange);
exchange.endExchange();
}

return outcome != null ? outcome : NOT_AUTHENTICATED;

 

JBoss EAP/WildFly

JBoss identity stores are based on the JAAS LoginModule, which is shown below:


public interface LoginModule {
void initialize(Subject subject, CallbackHandler callbackHandler, Map<String,?> sharedState, Map<String,?> options);
boolean login() throws LoginException;
boolean commit() throws LoginException;
boolean abort() throws LoginException;
boolean logout() throws LoginException;
}
As with most application servers, the JAAS LoginModule interface is used in a highly application server specific way.

It's a big question why this interface is used at all, since you can't just implement that interface. Instead you have to inherit from a credential specific base class. Therefor the LoginModule interface is practically an internal implementation detail here, not something the user actually uses. Despite that, it's not uncommon for users to think "plain" JAAS is being used and that JAAS login modules are universal and portable, but they are anything but.

For the username/password credential the base class to inherit from is UsernamePasswordLoginModule. As per the JavaDoc of this class, there are two methods that need to be implemented: getUsersPassword() and getRoleSets().

getUsersPassword() has to return the actual password for the provided username, so the base code can compare it against the provided password. If those passwords match getRoleSets() is called to retrieve the roles associated with the username. Note that JBoss typically does not map groups to roles, so it returns roles here which are then later on passed into APIs that normally would expect groups. In both methods the username is available via a call to getUsername().

The "real" contract as *hypothetical* interface could be thought of to look as follows:


public interface JBossIdentityStore {
String getUsersPassword(String username);
Group[] getRoleSets(String username) throws LoginException;
}

Example of usage

There's no direct usage of the LoginModule in JBoss. JBoss EAP 7/WildFly 8-9-10 directly uses Undertow as its Servlet container, which means the authentication mechanisms shipped with that uses the IdentityManager interface exactly as shown above in the Undertow section.

For usage in JBoss there's a bridge implementation of the IdentityManager to the JBoss specific JAAS LoginModule available.

The "identityManager.verify(userName, credential)" call shown above ends up at JAASIdentityManagerImpl#verify. This first wraps the username, but extracts the password from PasswordCredential. Abbreviated it looks as follows:


public Account verify(String id, Credential credential) {
if (credential instanceof DigestCredential) {
// ..
} else if(credential instanceof PasswordCredential) {
return verifyCredential(
new AccountImpl(id),
copyOf(((PasswordCredential) credential).getPassword())

);
}
return verifyCredential(new AccountImpl(id), credential);
}
The next method called in the "password chain" is somewhat troublesome, as it doesn't just return the account details, but as an unavoidable side-effect also puts the result of authentication in TLS. It takes a credential as an Object and delegates further to an isValid() method. This one uses a Subject as an output parameter (meaning it doesn't return the authentication data but puts it inside the Subject that's passed in). The calling method then extracts this authentication data from the subject and puts it into its own type instead.

Abbreviated again this looks as follows:


private Account verifyCredential(AccountImpl account, Object credential)
Subject subject = new Subject();
boolean isValid = securityDomainContext
.getAuthenticationManager()
.isValid(account.getOriginalPrincipal(), credential, subject);

if (isValid) {

// Stores details in TLS
getSecurityContext()
.getUtil()
.createSubjectInfo(account.getOriginalPrincipal(), credential, subject);

return new AccountImpl(
getPrincipal(subject), getRoles(subject),
credential, account.getOriginalPrincipal()
);
}

return null;
}
The next method being called is isValid() on a type called AuthenticationManager. Via two intermediate methods this ends up calling proceedWithJaasLogin.

This method obtains a LoginContext, which wraps a Subject, which wraps the Principal and roles shown above (yes, there's a lot of wrapping going on). Abbreviated the method looks as follows:


private boolean proceedWithJaasLogin(Principal principal, Object credential, Subject theSubject) {
try {
copySubject(defaultLogin(principal, credential).getSubject(), theSubject);
return true;
} catch (LoginException e) {
return false;
}
}

The defaultLogin() method finally just calls plain Java SE JAAS code, although just before doing that it uses reflection to call a setSecurityInfo() method on the CallbackHandler. It's remarkable that even though this method seems to be required and known in advance, there's no interface used for this. The handler being used here is often of the type JBossCallbackHandler.

Brought back to its essence the method looks like this:


private LoginContext defaultLogin(Principal principal, Object credential) throws LoginException {

CallbackHandler theHandler = (CallbackHandler) handler.getClass().newInstance();
setSecurityInfo.invoke(theHandler, new Object[] {principal, credential});

LoginContext lc = new LoginContext(securityDomain, subject, handler);
lc.login();

return lc;
}

Via some reflective magic the JAAS code shown here will locate, instantiate and at long last will call our custom LoginModule's initialize(), login() and commit() methods, which on their turn will call the two methods that we needed to implement in our subclass.

 

Resin

Resin calls its identity store "Authenticator". It's represented by a single interface shown below:


public interface Authenticator {
String getAlgorithm(Principal uid);
Principal authenticate(Principal user, Credentials credentials, Object details);
boolean isUserInRole(Principal user, String role);
void logout(Principal user);
}
There are a few things to remark here. The logout() method doesn't seem to make much sense, since it's the authentication mechanism that keeps track of the login state in the overarching server. Indeed, the method does not seem to be called by Resin, and there are no identity stores implementing it except for the AbstractAuthenticator that does nothing there.

isUserInRole() is somewhat remarkable as well. This method is not intended to check for the roles of any given user, such as you could for instance use in an admin UI. Instead, it's intended to be used by the HttpServletRequest#isUserInRole call, and therefor only for the *current* user. This is indeed how it's used by Resin. This is remarkable, since most other systems keep the roles in memory. Retrieving it from the identity store every time can be rather heavyweight. To combat this, Resin uses a CachingPrincipal, but an identity store implementation has to opt-in to actually use this.

Example of usage

The code below shows an example of how Resin actually uses its identity store. The following shortened fragment is taken from the implementation of the Servlet FORM authentication mechanism in Resin.


// Obtain reference to identity store
Authenticator auth = getAuthenticator();

// ..

String userName = request.getParameter("j_username");
String passwordString = request.getParameter("j_password");

if (userName == null || passwordString == null)
return null;

char[] password = passwordString.toCharArray();
BasicPrincipal basicUser = new BasicPrincipal(userName);
Credentials credentials = new PasswordCredentials(password);

// Delegating of authentication mechanism to identity store
user = auth.authenticate(basicUser, credentials, request);

return user;

A nice touch here is that Resin obtains the identity store via CDI injection. A somewhat unknown fact is that Resin has its own CDI implementation, CanDI and uses it internally for a lot of things. Unlike some other servers, the call to authenticate() here goes straight to the identity store. There are no layers of lookup or bridge code in between.

That said, Resin does encourage (but not require) the usage of an abstract base class it provides: AbstractAuthenticator. IFF this base class is indeed used (again, this is not required), then there are a few levels of indirection the flow goes through before reaching one's own code. In that case, the authenticate() call shown above will start with delegating to one of three methods for known credential types. This is shown below:


public Principal authenticate(Principal user, Credentials credentials, Object details) {
if (credentials instanceof PasswordCredentials)
return authenticate(user, (PasswordCredentials) credentials, details);
if (credentials instanceof HttpDigestCredentials)
return authenticate(user, (HttpDigestCredentials) credentials, details);
if (credentials instanceof DigestCredentials)
return authenticate(user, (DigestCredentials) credentials, details);
return null;
}

Following the password trail, the next level will merely extract the password string:


protected Principal authenticate(Principal principal, PasswordCredentials cred, Object details) {
return authenticate(principal, cred.getPassword());
}

The next authenticate method will call into a more specialized method that only obtains a User instance from the store. This instance has the expected password embedded, which is then verified against the provided password. Abbreviated it looks as follows:


protected Principal authenticate(Principal principal, char[] password) {
PasswordUser user = getPasswordUser(principal);

if (user == null || user.isDisabled() || (!isMatch(principal, password, user.getPassword()) && !user.isAnonymous()))
return null;

return user.getPrincipal();
}

The getPasswordUser() method goes through one more level of convenience, where it extracts the caller name that was wrapped by the Principal:


protected PasswordUser getPasswordUser(Principal principal) {
return getPasswordUser(principal.getName());
}

This last call to getPasswordUser(String) is what typically ends up in our own custom identity store.

Finally, it's interesting to see what data PasswordUser contains. Abbreviated again this is shown below:


public class PasswordUser {
Principal principal;
char[] password;

boolean disabled;
boolean anonymous;
String[] roles;
}

 

Glassfish

GlassFish identity stores are based on the JAAS LoginModule, which is shown below:


public interface LoginModule {
void initialize(Subject subject, CallbackHandler callbackHandler, Map<String,?> sharedState, Map<String,?> options);
boolean login() throws LoginException;
boolean commit() throws LoginException;
boolean abort() throws LoginException;
boolean logout() throws LoginException;
}

Just as we saw with JBoss above, the LoginModule interface is again used in a very application server specific way. In practice, you don't just implement a LoginModule but inherit from com.sun.enterprise.security.BasePasswordLoginModule or it's empty subclass com.sun.appserv.security.AppservPasswordLoginModule for password based logins, or com.sun.appserv.security.AppservCertificateLoginModule/com.sun.enterprise.security.BaseCertificateLoginModule for certificate ones.

As per the JavaDoc of those classes, the only method that needs to be implemented is authenticateUser(). Inside that method the username is available via the protected variable(!) "_username", while the password can be obtained via getPasswordChar(). When a custom identity store is done with its work commitUserAuthentication() has to be called with an array of groups when authentication succeeded and a LoginException thrown when it failed. So essentially that's the "real" contract for a custom login module. The fact that the other functionality is in the same class is more a case of using inheritance where aggregation might have made more sense. As we saw with JBoss, the LoginModule interface itself seems more like an implementation detail instead of something a client can really take advantage of.

The "real" contract as *hypothetical* interface looks as follows:


public interface GlassFishIdentityStore {
String[] authenticateUser(String username, char[] password) throws LoginException;
}

Even though a LoginModule is specific for a type of identity store (e.g. File, JDBC/database, LDAP, etc), LoginModules in GlassFish are mandated to be paired with another construct called a Realm. While having the same name as the Tomcat equivalent and even a nearly identical description, the type is completely different. In GlassFish it's actually a kind of DAO, albeit one with a rather heavyweight contract.

Most of the methods of this DAO are not actually called by the runtime for authentication, nor are they used by application themselves. They're likely intended to be used by the GlassFish admin console, so a GlassFish administrator can add and delete users. However, very few actual realms support this and with good reason. It just doesn't make much sense for many realms really. E.g. LDAP and Solaris have their own management UI already, and JDBC/database is typically intended to be application specific so there the application already has its own DAOs and services to manage users, and exposes its own UI as well.

A custom LoginModule is not forced to use this Realm, but the base class code will try to instantiate one and grab its name, so one must still be paired to the LoginModule.

The following lists the public and protected methods of this Realm class. Note that the body is left out for the non-abstract methods.


public abstract class Realm implements Comparable {

public static synchronized Realm getDefaultInstance();
public static synchronized String getDefaultRealm();
public static synchronized Enumeration getRealmNames();
public static synchronized void getRealmStatsProvier();
public static synchronized Realm getInstance(String);
public static synchronized Realm instantiate(String, File);
public static synchronized Realm instantiate(String, String, Properties);
public static synchronized void setDefaultRealm(String);
public static synchronized void unloadInstance(String);
public static boolean isValidRealm(String);
protected static synchronized void updateInstance(Realm, String);

public abstract void addUser(String, String, String[]);
public abstract User getUser(String);
public abstract void updateUser(String, String, String, String[]);
public abstract void removeUser(String);

public abstract Enumeration getUserNames();
public abstract Enumeration getGroupNames();
public abstract Enumeration getGroupNames(String);

public abstract void persist();
public abstract void refresh();

public abstract AuthenticationHandler getAuthenticationHandler();
public abstract boolean supportsUserManagement();
public abstract String getAuthType();

public int compareTo(Object);
public String FinalgetName();
public synchronized String getJAASContext();
public synchronized String getProperty(String);
public synchronized void setProperty(String, String);

protected void init(Properties);
protected ArrayList<String> getMappedGroupNames(String);
protected String[] addAssignGroups(String[]);
protected final void setName(String);
protected synchronized Properties getProperties();
}

Example of usage

To make matters a bit more complicated, there's no direct usage of the LoginModule in GlassFish either. GlassFish' Servlet container is internally based on Tomcat, and therefor the implementation of the FORM authentication mechanism is a Tomcat class (which strongly resembles the class in Tomcat itself, but has small differences here and there). Confusingly, this uses a class named Realm again, but it's a totally different Realm than the one shown above. This is shown below:


// Obtain reference to identity store
Realm realm = context.getRealm();

String username = hreq.getParameter(FORM_USERNAME);
String pwd = hreq.getParameter(FORM_PASSWORD);
char[] password = ((pwd != null)? pwd.toCharArray() : null);

// Delegating of authentication mechanism to identity store
principal = realm.authenticate(username, password);

if (principal == null) {
forwardToErrorPage(request, response, config);
return (false);
}

if (session == null)
session = getSession(request, true);

session.setNote(FORM_PRINCIPAL_NOTE, principal);

This code is largely identical to the Tomcat version shown above. The Tomcat Realm in this case is not the identity store directly, but an adapter called RealmAdapter. It first calls the following slightly abbreviated method for the password credential:


public Principal authenticate(String username, char[] password) {
if (authenticate(username, password, null)) {
return new WebPrincipal(username, password, SecurityContext.getCurrent());
}
return null;
}
Which on its turn calls the following abbreviated method that handles two supported types of credentials:

protected boolean authenticate(String username, char[] password, X509Certificate[] certs) {
try {
if (certs != null) {
// ... create subject
LoginContextDriver.doX500Login(subject, moduleID);
} else {
LoginContextDriver.login(username, password, _realmName);
}
return true;
} catch (Exception le) {}

return false;
}
Again (strongly) abbreviated the login method called looks as follows:

public static void login(String username, char[] password, String realmName){
Subject subject = new Subject();
subject.getPrivateCredentials().add(new PasswordCredential(username, password, realmName));

LoginContextDriver.login(subject, PasswordCredential.class);
}

This new login method checks for several credential types, which abbreviated looks as follows:


public static void login(Subject subject, Class cls) throws LoginException {
if (cls.equals(PasswordCredential.class))
doPasswordLogin(subject);
else if (cls.equals(X509CertificateCredential.class))
doCertificateLogin(subject);
else if (cls.equals(AnonCredential.class)) {
doAnonLogin();
else if (cls.equals(GSSUPName.class)) {
doGSSUPLogin(subject);
else if (cls.equals(X500Name.class)) {
doX500Login(subject, null);
else
throw new LoginException("Unknown credential type, cannot login.");
}

As we're following the password trail, we're going to look at the doPasswordLogin() method here, which strongly abbreviated looks as follows:


private static void doPasswordLogin(Subject subject) throws LoginException
try {
new LoginContext(
Realm.getInstance(
getPrivateCredentials(subject, PasswordCredential.class).getRealm()
).getJAASContext(),
subject,
dummyCallback
).login();
} catch (Exception e) {
throw new LoginException("Login failed: " + e.getMessage()).initCause(e);
}
}

We're now 5 levels deep, and we're about to see our custom login module being called.

At this point it's down to plain Java SE JAAS code. First the name of the realm that was stuffed into a PasswordCredential which was stuffed into a Subject is used to obtain a Realm instance of the type that was shown way above; the GlassFish DAO like type. Via this instance the realm name is mapped to another name; the "JAAS context". This JAAS context name is the name under which our LoginModule has to be registered. The LoginContext does some magic to obtain this LoginModule from a configuration file and initializes it with the Subject among others. The login(), commit() and logout() methods can then make use of this Subject later on.

At long last, the login() method call (via 2 further private helper methods, not shown here) will at 7 levels deep cause the login() method of our LoginModule to be called. This happens via reflective code which looks as follows:


// methodName == "login" here

// find the requested method in the LoginModule
for (mIndex = 0; mIndex < methods.length; mIndex++) {
if (methods[mIndex].getName().equals(methodName))
break;
}

// set up the arguments to be passed to the LoginModule method
Object[] args = { };

// invoke the LoginModule method
boolean status = ((Boolean) methods[mIndex].invoke(moduleStack[i].module, args)).booleanValue();
But remember that in GlassFish we didn't directly implemented LoginModule#login() but the abstract authenticateUser() method of the BasePasswordLoginModule, so we still have one more level to go. The final call at level 8 that causes our very own custom method to be called can be seen below:

final public boolean login() throws LoginException {

// Extract the username, password and realm name from the Subject
extractCredentials();

// Delegate the actual authentication to subclass (finally!)
authenticateUser();

return true;
}

 

Liberty

Liberty calls its identity stores "user registry". It's shown below:


public interface UserRegistry {
void initialize(Properties props) throws CustomRegistryException, RemoteException;

String checkPassword(String userSecurityName, String password) throws PasswordCheckFailedException, CustomRegistryException, RemoteException;
String mapCertificate(X509Certificate[] certs) throws CertificateMapNotSupportedException, CertificateMapFailedException, CustomRegistryException, RemoteException;
String getRealm() throws CustomRegistryException, RemoteException;

Result getUsers(String pattern, int limit) throws CustomRegistryException, RemoteException;
String getUserDisplayName(String userSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException;
String getUniqueUserId(String userSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException;
String getUserSecurityName(String uniqueUserId) throws EntryNotFoundException, CustomRegistryException, RemoteException;
boolean isValidUser(String userSecurityName) throws CustomRegistryException, RemoteException;

Result getGroups(String pattern, int limit) throws CustomRegistryException, RemoteException;
String getGroupDisplayName(String groupSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException;
String getUniqueGroupId(String groupSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException;
List getUniqueGroupIds(String uniqueUserId) throws EntryNotFoundException, CustomRegistryException, RemoteException;
String getGroupSecurityName(String uniqueGroupId) throws EntryNotFoundException, CustomRegistryException, RemoteException;
boolean isValidGroup(String groupSecurityName) throws CustomRegistryException, RemoteException;

List getGroupsForUser(String groupSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException;
WSCredential createCredential(String userSecurityName) throws NotImplementedException, EntryNotFoundException, CustomRegistryException, RemoteException;    
}

As can be seen it's clearly one of the most heavyweight interfaces for an identity store that we've seen till this far. As Liberty is closed source we can't exactly see what the server uses all these methods for.

As can be seen though it has methods to list all users and groups that the identity store manages (getUsers(), getGroups()) as well as methods to get what IBM calls a "display name", "unique ID" and "security name" which are apparently associated with both user and role names. According to the published JavaDoc display names are optional. It's perhaps worth it to ask the question if the richness that these name mappings potentially allow for are worth the extra complexity that's seen here.

createCredential() stands out as the JavaDoc mentions it's never been called for at least the 8.5.5 release of Liberty.

The main method that does the actual authentication is checkPassword(). It's clearly username/password based. Failure has to be indicated by trowing an exception, success returns the passed in username again (or optionally any other valid name, which is a bit unlike what most other systems do). There's support for certificates via a separate method, mapCertificate(), which seemingly has to be called first, and then the resulting username passed into checkPassword() again.

Example of usage

Since Liberty is closed source we can't actually see how the server uses its identity store. Some implementation examples are given by IBM and myself.

 

WebLogic

It's not entirely clear what an identity store in WebLogic is really called. There are many moving parts. The overall term seems to be "security provider", but these are subdivided in authentication providers, identity assertion providers, principal validation providers, authorization providers, adjudication providers and many more providers.

One of the entry points seems to be an "Authentication Provider V2", which is given below:


public interface AuthenticationProviderV2 extends SecurityProvider {

AppConfigurationEntry getAssertionModuleConfiguration();
IdentityAsserterV2 getIdentityAsserter();
AppConfigurationEntry getLoginModuleConfiguration();
PrincipalValidator getPrincipalValidator();
}

Here it looks like the getLoginModuleConfiguration() has to return an AppConfigurationEntry that holds the fully qualified class name of a JAAS LoginModule, which is given below:


public interface LoginModule {
void initialize(Subject subject, CallbackHandler callbackHandler, Map<String,?> sharedState, Map<String,?> options);
boolean login() throws LoginException;
boolean commit() throws LoginException;
boolean abort() throws LoginException;
boolean logout() throws LoginException;
}
ItseemsWebLogic's usage of the LoginModule is not as highly specific to the application server as we saw was the case for JBoss and GlassFish. The user can implement the interface directly, but has to put WebLogic specific principals in the Subject as these are not standardized.

Example of usage

Since WebLogic is closed source it's not possible to see how it actually uses the Authentication Provider V2 and its associated Login Module.

 

Conclusion

We took a look at how a number of different servlet containers implemented the identity store concept. The variety of ways to accomplish essentially the same thing is nearly endless. Some containers pass two strings for a username and password, others pass a String for the username, but a dedicated Credential type for the password, a char[] or even an opaque Object for the password. Two containers pass in a third parameter; the http servlet request.

The return type is varied as well. A (custom) Principal was used a couple of times, but several other representations of "caller data" were seen as well; like an "Account" and a "UserIdentity". In one case the container deemed it necessary to modify TLS to set the result.

The number of levels (call depth) needed to go through before reaching the identity store was different as well between containers. In some cases the identity store was called immediately with absolutely nothing in between, while in other cases up to 10 levels of bridging, adapting and delegating was done before the actual identity store was called.

Taking those intermediate levels into account revealed even more variety. We saw complete LoginContext instances being returned, we saw Subjects being used as output parameters, etc. Likewise, the mechanism to indicate success or failure ranged from an exception being thrown, via a boolean being returned, to a null being returned for groups.

One thing that all containers had in common though was that there's always an authentication mechanism that interacts with the caller and environment and delegates to the identity store. Then, no matter how different the identity store interfaces looked, every one of them had a method to perform the {credentials in, caller data out} function.

It's exactly this bare minimum of functionality that is arguably in most dire need of being standardised in Java EE. As it happens to be the case this is indeed what we're currently looking at in the security EG.

Arjan Tijms


The state of portable authentication for GlassFish, Payara, JBoss/WildFly, WebLogic and Liberty

$
0
0
Almost exactly 3 years ago I took an initial look at custom container authentication in Java EE. Java EE has a dedicated API for this called JASPIC. Even though JASPIC was a mandatory part of Java EE, support at the time was not really good. In this article we'll take a look at where things were and how things are in the current crop of servers in 2015.

To begin with, there were a number of spec omissions in JASPIC 1.0 (Java EE 6). The biggest one was that in order to register a server authentication module (SAM) an application ID had to be provided. This ID could not be obtained in a portable way. The JASPIC 1.1 MR rectified this.

Other spec omissions concerned JASPIC being silent about what would need to happen with respect to HttpServletRequest#login and HttpServletRequest#logout, and with forward and includes done from a SAM. The JASPIC 1.1 MR rectified these omissionstoo.

With respect to the actual behaviour there were a large number of very serious problems. Most concerned the very basic stateless nature of JASPIC. A JASPIC SAM is like a Servlet Filter; it's called for every request to both public and protected resources, and doesn't automatically create a session when a caller is authenticated. What actually happened differed per server back then. Some only called the SAM for protected resources, some automatically created a session and never called the SAM again, etc.

Another class of problems concerned the life cycle. A SAM has two seemingly simple methods; "validateRequest" that has to be called before Filters and Servlets are invoked, and "secureResponse" that has to be called after. Especially this "after" was ill understood. Some servers called "validateRequest" and "secureResponse" both before the Filters right after each other, while others called "secureResponse" every time data was written to the response.

A specifically peculiar thing was that no server back then was able to wrap the request and response, even though the JASPIC spec clearly states that this is required. Accessing resources from a SAM, such as EJB beans or datasources via JNDI, or CDI beans via the bean manager was a hit or miss as well. Basically every server behaved differently there.

Finally there were big issues with interpreting how portable a SAM should exactly be, and whether the technology should "just be there", or whether some server specific configuration had to be done first. One vendor seemingly interpreted the JASPIC spec as a portable "authentication mechanism" (the artefact that interacts with the user, such as Servlet's FORM), that then delegated to a proprietary (server specific) "identity store" (the artefact that stores the user data and groups, such as LDAP or a database).

In response to this I created a series of tests, that were later donated to the Java EE 7 samples project. Subsequently I worked with all vendors and asked them to improve their JASPIC implementations. With the exception of Geronimo all vendors were very cooperative, so I'd like to take the opportunity here to give them all a big thanks for their hard work.

So after 3 years of creating tests and reporting issues, what's the current situation like? To find out I executed the JASPIC tests against the current crop of servers. The result is shown below:

Running the Java EE 7 samples JASPIC tests
ModuleTestGlassFish 4.1.1Payara 4.1.1.154JBoss EAP 7 alpha1
WildFly 10rc4
WebLogic 12.2.1Liberty 8.5.5.7
9 beta 2015.10
lifecycletestBasicSAMMethodsCalled
Passed
Passed
Passed
Passed
Passed
lifecycletestLogout
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedPageNotLoggedin
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedPageLoggedin
Passed
Passed
Passed
Failure
Passed
basic-authenticationtestPublicPageLoggedin
Passed
Passed
Passed
Failure
Passed
basic-authenticationtestPublicPageNotLoggedin
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestPublicAccessIsStateless
Passed
Passed
Passed
Failure
Passed
basic-authenticationtestProtectedAccessIsStateless
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedAccessIsStateless2
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedThenPublicAccessIsStateless
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFwithCDIForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFwithCDIForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFIncludeViaPublicResource
Failure
Failure
Failure
Failure
Failure
dispatching-jsf-cditestJSFForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cditestCDIForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cditestCDIForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cditestCDIIncludeViaPublicResource
Passed
Passed
Passed
Passed
Failure
dispatching-jsf-cditestJSFwithCDIIncludeViaPublicResource
Failure
Failure
Failure
Failure
Failure
dispatchingtestBasicIncludeViaPublicResource
Passed
Passed
Passed
Passed
Failure
dispatchingtestBasicForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
dispatchingtestBasicForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
custom-principaltestPublicPageLoggedin
Failure
Passed
Passed
Failure
Passed
custom-principaltestPublicAccessIsStateless
Passed
Passed
Passed
Failure
Passed
custom-principaltestProtectedAccessIsStateless
Passed
Passed
Passed
Passed
Passed
custom-principaltestProtectedAccessIsStateless2
Passed
Passed
Passed
Passed
Passed
custom-principaltestProtectedThenPublicAccessIsStateless
Passed
Passed
Passed
Passed
Passed
custom-principaltestProtectedPageLoggedin
Failure
Passed
Passed
Failure
Passed
invoke-ejb-cdiprotectedInvokeCDIFromSecureResponse
Passed
Passed
Passed
Failure
Failure
invoke-ejb-cdiprotectedInvokeCDIFromCleanSubject
Passed
Passed
Passed
Passed
Failure
invoke-ejb-cdiprotectedInvokeCDIFromValidateRequest
Passed
Passed
Passed
Failure
Failure
invoke-ejb-cdiprotectedInvokeEJBFromSecureResponse
Failure
Failure
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeEJBFromCleanSubject
Passed
Passed
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeEJBFromValidateRequest
Failure
Failure
Passed
Passed
Passed
invoke-ejb-cdipublicInvokeEJBFromSecureResponse
Failure
Failure
Passed
Passed
Passed
invoke-ejb-cdipublicInvokeEJBFromValidateRequest
Failure
Failure
Passed
Passed
Passed
invoke-ejb-cdipublicInvokeEJBFromCleanSubject
Passed
Passed
Passed
Passed
Passed
invoke-ejb-cdipublicInvokeCDIFromSecureResponse
Passed
Passed
Passed
Failure
Failure
invoke-ejb-cdipublicInvokeCDIFromValidateRequest
Passed
Passed
Passed
Failure
Failure
invoke-ejb-cdipublicInvokeCDIFromCleanSubject
Passed
Passed
Passed
Passed
Passed
register-sessiontestJoinSessionIsOptional
Passed
Passed
Passed
Failure
Passed
register-sessiontestRemembersSession
Passed
Passed
Passed
Failure
Passed
async-authenticationtestBasicAsync
Passed
Passed
Passed
Passed
Passed
ejb-propagationpublicServletCallingPublicEJBThenLogout
Passed
Passed
Passed
Failure
Passed
ejb-propagationprotectedServletCallingProtectedEJB
Passed
Passed
Passed
Failure
Passed
ejb-propagationprotectedServletCallingPublicEJB
Passed
Passed
Passed
Failure
Passed
ejb-propagationpublicServletCallingProtectedEJB
Passed
Passed
Passed
Failure
Passed
wrappingtestResponseWrapping
Passed
Passed
Passed
Passed
Passed
wrappingtestRequestWrapping
Passed
Passed
Passed
Passed
Passed

 

As can be seen the situation has greatly improved. With the unfortunate exception of WebLogic 12.2.1 the basics now work everywhere. WebLogic 12.2.1 is perhaps a special case as it seems to be hit by a major bug where the most basic version of authentication doesn't work anymore, while it did work in the previous version 12.1.3. The fact that "testProtectedPageLoggedin" and "testPublicPageLoggedin" fail mean that actual authentication doesn't work properly. In this specific case it appears that when a caller authenticates with name "test" and gets the role "architect", then those are not available to the application. E.g. request#getUserPrincipal() still returns null and request#isUserInRole() returns false. This unfortunately means that for the moment until this bug is fixed JASPIC can not really be used on WebLogic at all.

Looking further at the results we see that the seemingly difficult to understand "secureResponse" method is now always called at the correct moment, and wrapping the request and response that once no server was able to do is now working well in all servers.

Forwards are now supported by all servers as are logouts. Includes are supported by most servers, only Liberty seems to have some issues with these. Curiously no server is able to include a resource that uses JSF. This is likely a JSF issue (as a JSF EG member and Mojarra committer this is something I probably have to fix myself ;))

Invoking resources has improved somewhat, but remains troublesome. Neither EJB beans nor CDI beans can be obtained and invoked on every server. EJB (specially those in the app scope such as java:comp, java:app, etc) work on JBoss EAP/WildFly, WebLogic and Liberty, but not on GlassFish and derivative Payara. CDI beans work in GlassFish, Payara and WildFly, but not in WebLogic and Liberty. WildFly is the one server where they both work.

The resources situation is still a spec issue as well and JASPIC 1.1 remains silent on whether this should work or not. The spec lead has clarified that even though the spec is silent on accessing EJB beans and other resources from the web component's JNDI namespaces, this is something that ought to work and GlassFish' current behaviour is just a bug. A next revision of the JASPIC spec should clarify this though. For the CDI beans no such clarification has been given, so vendors can't be asked to support this based on what the spec requires. However, accessing CDI from a SAM is very likely going to be a requirement coming from JSR 375 (Java EE security). So even though JASPIC doesn't mandate this now, it would be good if vendors already supported this in order to be prepared for Java EE 8.

Another case worth looking at is providing a custom principal from a SAM. This is a feature of JASPIC where a SAM can provide its own custom principal, e.g. org.example.MyPrincipal, which then has to be returned from request#getUserPrincipal(). This works on most servers except on GlassFish. It currently also doesn't work on WebLogic, but without further investigation it's hard to say whether it doesn't support this at all, or just because of the earlier failure of making the principal (custom or not) available.

From the outcome of the tests shown above it would seem JBoss EAP/WildFly clearly has the best JASPIC implementation, but there's one small but very important detail not shown in that table; the question whether JASPIC needs to be activated in a proprietary way. Unfortunately, JBoss EAP/WildFly indeeds needs such activation. If this activation would entail placing a special configuration file in the application archive it wouldn't be so bad, but JBoss EAP/WildFly actually requires the container to be modified before JASPIC can be used. This therefor means a SAM can not be deployed to a stock JBoss EAP/WildFly, which is very unfortunate indeed. There's a programmatic workaround available that doesn't require the container to be modified (see the activation link), but this is rather hacky and may break with every new release of JBoss EAP/WildFly.

The other server that needs server specific configuration is Liberty. Earlier versions of Liberty required all users and groups that a JASPIC SAM handles to be known by Liberty's proprietary user registry. An often downright impossible requirement in general and specifically for fully portable SAMs, and one that even violates the JASPIC spec. The current versions of Liberty have somewhat improved the situation by only requiring groups to be made known to Liberty. While still a very unfortunate requirement, it's at least possible to do this. Still, listing all the groups that an application uses in a proprietary file inside the container is a bit anti to one of the major use cases for which JASPIC is used; portable and application managed custom authentication. Instead of listing all the groups there's a workaround available where a NOOP user registry is installed and configured.

Conclusion

JBoss EAP 7/WildFly 10rc4 are almost perfect, if only JASPIC worked out of the box or could be activated from within the application archive using a configuration file. Payara 4.1.1.154 is another very good server for JASPIC. Here JASPIC works out of the box, but it suffers from a somewhat nasty bug that prevents it from using application scoped JNDI namespaces. GlassFish 4.1.1 is almost as good, but suffers from an extra bug that prevents it from using custom principals.

Liberty is quite good as well. It has slightly more bugs to fix than JBoss and Payara, but about the same as GlassFish. GlassFish can't use custom principals, Liberty can't do includes. Both can't obtain and invoke a specific bean type (for GlassFish this is EJB, for Liberty it's CDI). But above all Liberty suffers from its conflicting user registry requirement, although by far not as badly as before.

WebLogic 12.2.1 can at the moment not be recommended for JASPIC. It suffers from a severe bug that prohibits an application to use the authenticated identity, which is the core of what JASPIC does. Hopefully the WebLogic team is able to squash this particular bug soon.

All in all we've seen there's a steady and definite improvement going on for the various JASPIC implementations, but as can be seen there's still room left for improvement.

Arjan Tijms

Latest versions Payara and WildFly improve Java EE 7 authentication compliance

$
0
0
Two months ago we looked at the state of portable authentication for GlassFish, Payara, JBoss/WildFly, WebLogic and Liberty in Java EE 7. With the exception of WebLogic 12.2.1, most servers performed pretty well, but there were still a number of bugs present.

Since then both Payara and WildFly have seen bug fixes that again reduce the number of bugs present where it concerns portable Java EE authentication. Do note that both updated servers have not had an official (supported) release yet, but pre-release resp. rc/cr builds containing those fixes can be downloaded from the vendors.

In anticipation of the final version of those Java EE 7 servers we already took a look at how they improved. The results are shown in the table below. For reference we show several older versions as well. For Payara we took the GlassFish release upon which Payara based its additional fixes, while for WildFly it's a selection of older builds. (no less than 29 builds were released for WildFly 8,9,10/EAP 7 alpha,beta).

Running the Java EE 7 samples JASPIC tests
ModuleTestPayara 4.1.1.161-preGlassFish 4.1.1WildFly 10rc5WildFly 10rc4WildFly 9.0.1WildFly 8.0.0
async-authenticationtestBasicAsync
Passed
Passed
Passed
Passed
Passed
Failed
basic-authenticationtestProtectedPageNotLoggedin
Passed
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedPageLoggedin
Passed
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestPublicPageLoggedin
Passed
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestPublicPageNotLoggedin
Passed
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestPublicAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedAccessIsStateless2
Passed
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedThenPublicAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
custom-principaltestProtectedPageLoggedin
Passed
Failure
Passed
Passed
Passed
Passed
custom-principaltestPublicPageLoggedin
Passed
Failure
Passed
Passed
Passed
Passed
custom-principaltestPublicAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
custom-principaltestProtectedAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
custom-principaltestProtectedAccessIsStateless2
Passed
Passed
Passed
Passed
Passed
Passed
custom-principaltestProtectedThenPublicAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
dispatchingtestBasicForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatchingtestBasicForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatchingtestBasicIncludeViaPublicResource
Passed
Passed
Passed
Passed
Passed
Failure
dispatching-jsf-cditestCDIForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cditestCDIForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cditestCDIIncludeViaPublicResource
Passed
Passed
Passed
Passed
Passed
Failure
dispatching-jsf-cditestJSFwithCDIForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFwithCDIForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFwithCDIIncludeViaPublicResource
Failure
Failure
Failure
Failure
Failure
Failure
dispatching-jsf-cditestJSFForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFIncludeViaPublicResource
Failure
Failure
Failure
Failure
Failure
Failure
ejb-propagationpublicServletCallingProtectedEJB
Passed
Passed
Passed
Passed
Passed
Failure
ejb-propagationprotectedServletCallingProtectedEJB
Passed
Passed
Passed
Passed
Passed
Failure
ejb-propagationpublicServletCallingPublicEJBThenLogout
Passed
Passed
Passed
Passed
Passed
Failure
ejb-propagationprotectedServletCallingPublicEJB
Passed
Passed
Passed
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeCDIFromSecureResponse
Passed
Passed
Passed
Passed
Failure
Failure
invoke-ejb-cdiprotectedInvokeCDIFromCleanSubject
Passed
Passed
Passed
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeCDIFromValidateRequest
Passed
Passed
Passed
Passed
Passed
Passed
invoke-ejb-cdipublicInvokeCDIFromSecureResponse
Passed
Passed
Passed
Passed
Failure
Failure
invoke-ejb-cdipublicInvokeCDIFromValidateRequest
Passed
Passed
Passed
Passed
Passed
Passed
invoke-ejb-cdipublicInvokeCDIFromCleanSubject
Passed
Passed
Passed
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeEJBFromSecureResponse
Passed
Failure
Passed
Passed
Failure
Passed
invoke-ejb-cdiprotectedInvokeEJBFromCleanSubject
Passed
Passed
Passed
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeEJBFromValidateRequest
Passed
Failure
Passed
Passed
Passed
Passed
invoke-ejb-cdipublicInvokeEJBFromSecureResponse
Passed
Failure
Passed
Passed
Failure
Passed
invoke-ejb-cdipublicInvokeEJBFromValidateRequest
Passed
Failure
Passed
Passed
Passed
Passed
invoke-ejb-cdipublicInvokeEJBFromCleanSubject
Passed
Passed
Passed
Passed
Passed
Passed
jacc-propagationcallingJACCWhenAuthenticated
Passed
Passed
Failure
Failure
Failure
Failure
jacc-propagationcallingJACCWhenAuthenticated
Passed
Passed
Failure
Failure
Failure
Failure
jacc-propagationcallingJACCWhenNotAuthenticated
Passed
Passed
Passed
Passed
Passed
Passed
lifecycletestBasicSAMMethodsCalled
Passed
Passed
Passed
Passed
Failure
Passed
lifecycletestLogout
Passed
Passed
Passed
Passed
Passed
Passed
register-sessiontestJoinSessionIsOptional
Passed
Passed
Passed
Passed
Passed
Passed
register-sessiontestRemembersSession
Passed
Passed
Passed
Passed
Passed
Passed
status-codestest404inResponse
Passed
Passed
Passed
Failure
Failure
Passed
status-codestest404inResponse
Passed
Passed
Passed
Failure
Failure
Passed
wrappingtestResponseWrapping
Passed
Passed
Passed
Passed
Passed
Passed
wrappingtestRequestWrapping
Passed
Passed
Passed
Passed
Passed
Passed

Not shown in the table, but the absolute greatest improvement since JBoss switched to its new JASPIC implementation all the way back in WildFly 8.0.0.Alpha1 is the fact that JASPIC now finally works without the need of modifying WildFly by putting a dummy fragment in its standalone.xml file. It's not 100% perfect yet as the application archive (.war) still needs what is effectively a marker file to activate JASPIC, but this is much, much preferred over having to modify a server in order to activate a standard Java EE API that should just be there. Kudos to the JBoss team and a special thanks to Jason Greene for finally making this happen!

As can be seen, WildFly has seen many improvements over the years. Along the way a few regressions were introduced, but they were fixed again and now WildFly10rc5 is almost perfect with respect to the known bugs. Role propagation to JACC however still doesn't work. Although the usage of custom JACC providers is not that high, the test in question here uses the default provider for a rather useful query; "Can the authenticated user access a given resource?", e.g. "Can Pete access http://example.com/assets/someresource?".

The top performer as of now is Payarra, which passes all tests except for one of minor importance where a JSF based resource is included by an authentication module. As mentioned in the previous report this likely has to be fixed on the JSF side of things.

If all goes well we'll see a new beta of Liberty 9 this month which should also contain a number of fixes. The most problematic server at this moment is still WebLogic, which introduced a major regression between 12.1.3 and 12.2.1. Hopefully WebLogic will fix this regression soon. We'll repeat this test again when either of those publish their latest version.

Arjan Tijms

Java EE 7 server Liberty 9 beta 2016.1 tested for JASPIC support

$
0
0
IBM recently released the latest monthly beta of their modern and light weight Java EE 7 server; Liberty 9 beta 2016.1. Previous beta releases of Liberty 9 already performed quite well when it came to Java EE's portable authentication (JASPIC), but weren't perfect yet.

In this article we take a look to see if JASPIC support has improved in the latest release. To find out we executed the JASPIC tests against this latest release. For comparison the previous Liberty beta as well as the latest (snapshots) of Payara and WildFly are shown.

One thing to note is that previous downloads of recent Liberty betas were always for a full Java EE 7 server. For some inexplainable reason this month's beta is "only" a Java EE 7 web profile. Possibly this is a bug on the download page, as the size that as stated (116 mb) is not the same as the actual archive that's downloaded (94 mb).

One of Liberty's unique features is that it has a very elaborate and smooth system to install new components and their dependencies. In a way it's a bit like Maven dependency management but for the AS. With the help of this system the mysteriously missing Java EE 7 components could be installed after unpacking Liberty with the following command:


bin/installUtility install javaee-7.0
Additionally the so-called local connector was needed to run the tests. Previous betas included this as well, but it now had to be installed separately too:

bin/installUtility install localConnector-1.0

After this we could run the tests. The results are shown in the table below:

Running the Java EE 7 samples JASPIC tests
ModuleTestPayara 4.1.1.161-preWildFly 10rc5Liberty 9 beta 2016.1Liberty 9 beta 2015.11
async-authenticationtestBasicAsync
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedPageNotLoggedin
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedPageLoggedin
Passed
Passed
Passed
Passed
basic-authenticationtestPublicPageLoggedin
Passed
Passed
Passed
Passed
basic-authenticationtestPublicPageNotLoggedin
Passed
Passed
Passed
Passed
basic-authenticationtestPublicAccessIsStateless
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedAccessIsStateless
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedAccessIsStateless2
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedThenPublicAccessIsStateless
Passed
Passed
Passed
Passed
custom-principaltestProtectedPageLoggedin
Passed
Passed
Passed
Passed
custom-principaltestPublicPageLoggedin
Passed
Passed
Passed
Passed
custom-principaltestPublicAccessIsStateless
Passed
Passed
Passed
Passed
custom-principaltestProtectedAccessIsStateless
Passed
Passed
Passed
Passed
custom-principaltestProtectedAccessIsStateless2
Passed
Passed
Passed
Passed
custom-principaltestProtectedThenPublicAccessIsStateless
Passed
Passed
Passed
Passed
dispatchingtestBasicForwardViaProtectedResource
Passed
Passed
Passed
Passed
dispatchingtestBasicForwardViaPublicResource
Passed
Passed
Passed
Passed
dispatchingtestBasicIncludeViaPublicResource
Passed
Passed
Passed
Failure
dispatching-jsf-cditestCDIForwardViaProtectedResource
Passed
Passed
Passed
Passed
dispatching-jsf-cditestCDIForwardViaPublicResource
Passed
Passed
Passed
Passed
dispatching-jsf-cditestCDIIncludeViaPublicResource
Passed
Passed
Passed
Failure
dispatching-jsf-cditestJSFwithCDIForwardViaPublicResource
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFwithCDIForwardViaProtectedResource
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFwithCDIIncludeViaPublicResource
Failure
Failure
Failure
Failure
dispatching-jsf-cditestJSFForwardViaPublicResource
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFForwardViaProtectedResource
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFIncludeViaPublicResource
Failure
Failure
Failure
Failure
ejb-propagationpublicServletCallingProtectedEJB
Passed
Passed
Passed
Passed
ejb-propagationprotectedServletCallingProtectedEJB
Passed
Passed
Passed
Passed
ejb-propagationpublicServletCallingPublicEJBThenLogout
Passed
Passed
Passed
Passed
ejb-propagationprotectedServletCallingPublicEJB
Passed
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeCDIFromSecureResponse
Passed
Passed
Failure
Failure
invoke-ejb-cdiprotectedInvokeCDIFromCleanSubject
Passed
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeCDIFromValidateRequest
Passed
Passed
Failure
Failure
invoke-ejb-cdipublicInvokeCDIFromSecureResponse
Passed
Passed
Failure
Failure
invoke-ejb-cdipublicInvokeCDIFromValidateRequest
Passed
Passed
Failure
Failure
invoke-ejb-cdipublicInvokeCDIFromCleanSubject
Passed
Passed
Passed
Failure
invoke-ejb-cdiprotectedInvokeEJBFromSecureResponse
Passed
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeEJBFromCleanSubject
Passed
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeEJBFromValidateRequest
Passed
Passed
Passed
Passed
invoke-ejb-cdipublicInvokeEJBFromSecureResponse
Passed
Passed
Passed
Passed
invoke-ejb-cdipublicInvokeEJBFromValidateRequest
Passed
Passed
Passed
Passed
invoke-ejb-cdipublicInvokeEJBFromCleanSubject
Passed
Passed
Passed
Passed
jacc-propagationcallingJACCWhenAuthenticated
Passed
Failure
Failure
Failure
jacc-propagationcallingJACCWhenAuthenticated
Passed
Failure
Failure
Failure
jacc-propagationcallingJACCWhenNotAuthenticated
Passed
Passed
Failure
Failure
lifecycletestBasicSAMMethodsCalled
Passed
Passed
Passed
Passed
lifecycletestLogout
Passed
Passed
Passed
Passed
register-sessiontestJoinSessionIsOptional
Passed
Passed
Passed
Passed
register-sessiontestRemembersSession
Passed
Passed
Passed
Passed
status-codestest404inResponse
Passed
Passed
Passed
Passed
status-codestest404inResponse
Passed
Passed
Passed
Passed
wrappingtestResponseWrapping
Passed
Passed
Passed
Passed
wrappingtestRequestWrapping
Passed
Passed
Passed
Passed

As can be seen Liberty's JASPIC support has again improved. Including a resource (e.g. Servlet or JSP) into the response now generally works again. Only JSF based includes are still broken, but this is likely not a Liberty problem but a JSF one.

Additionally one CDI problem was fixed; obtaining and invoking a CDI bean from a SAM's cleanSubject method. This already worked on previous betas when the request was to a protected resource, but mysteriously failed for public resources. The cleanSubject method is generally somewhat easier to support, as this method is called in response to HttpServletRequest#logout and thus happens during the so-called resource invocation (i.e. from the context of a Servlet where CDI already is mandated to be available).

The real challenge for JASPIC implementors is to make sure that CDI works before and after this resource invocation. Payara, GlassFish and JBoss/WildFly have succeeded in supporting this, but Liberty not yet. This support is particularly important since the upcoming Java EE Security API (JSR 375) completely depends on the ability to obtain and invoke CDI beans from the validateRequest and secureResponse methods. Unfortunately early versions of the JSR 375 API can now not be tested on Liberty.

Conclusion

Liberty is improving rapidly and already very useful to deploy portable Java EE 7 authentication modules on. Hopefully it will soon take one the last hurdles and provide full support for CDI as well.

Arjan Tijms

Servlet 4.0's mapping API previewed in Tomcat 9.0 m4

$
0
0
Without doubt one of the most important Servlet implementations is done by Tomcat. Tomcat serves, or has served, as the base for Servlet functionality in a number of Java EE application servers and is one of the most frequently used standalone Servlet containers.

Contrary to what is often thought, Tomcat is not the reference implementation for Servlet; the build-in Servlet container of GlassFish is. Even though important parts of that GlassFish Servlet implementation are in fact based on Tomcat it's a different code base. Normally GlassFish being the RI implements new spec level functionality first, but unfortunately during the Java EE 8/Servlet 4.0 cycle the GlassFish team is working on other assignments and hasn't worked out a schedule to incorporate this new functionality.

Luckily Tomcat has taken the initiative and in Tomcat 9.0.0.M4 the proposed Servlet 4.0 Mapping API has been implemented.

This API allows Servlet users to find out via which mapping a Servlet was being called. E.g. a Servlet can be mapped by a user to both "/foo/*" and "*.bar" among others. Especially for frameworks it can be important to know what the mapping was, since not rarely something (typically a template file) has to be loaded based on what the * from the above example was. And not only that, if links have to be generated they often need to use the same mapping that was used to call the Servlet.

The current way to do this is a little hairy and therefor quite error prone; it requires checking against the many components of the request URI. The new proposed API greatly simplifies this via the new HttpServletRequest#getMapping() method:


public default Mapping getMapping() {
// ...
}
The new Mapping type that can be seen in the signature of the above method looks as follows:

/**
* Represents how the request from which this object was obtained was mapped to
* the associated servlet.
*
* @since 4.0
*/
public interface Mapping {

/**
* @return The value that was matched or the empty String if not known.
*/
String getMatchValue();

/**
* @return The {@code url-pattern} that matched this request or the empty
* String if not known.
*/
String getPattern();

/**
* @return The type of match ({@link MappingMatch#UNKNOWN} if not known)
*/
MappingMatch getMatchType();
}
The MappingMatch is an enumeration of the different types of possible mappings as shown below:

/**
* Represents the ways that a request can be mapped to a servlet
*
* @since 4.0
*/
public enum MappingMatch {

CONTEXT_ROOT,
DEFAULT,
EXACT,
EXTENSION,
IMPLICIT,
PATH,
UNKNOWN
}
To test out the new functionality the following test Servlet was used:

@WebServlet({"/path/*", "*.ext", "", "/", "/exact"})
public class Servlet extends HttpServlet {

private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

Mapping mapping = request.getMapping();

response.getWriter()
.append("Mapping match:")
.append(mapping.getMatchType().name())
.append("\n")
.append("Match value:")
.append(mapping.getMatchValue())
.append("\n")
.append("Pattern:")
.append(mapping.getPattern());
}

}

As can be seen this Servlet is mapped via a path mapping ("/path/*"), extension mapping ("*.ext"), context root mapping (""), default mapping ("/") and a single exact mapping ("/exact"). We deployed this Servlet via an application called "servlet4" to a Tomcat 9.0 M4 instance and subjected it to a couple of requests via a browser. The results are shown below:

Path mapping
http://localhost:8080/servlet4/path/foo


Mapping match:PATH
Match value:/foo
Pattern:/path/*

Extension mapping
http://localhost:8080/servlet4/foo.ext


Mapping match:EXTENSION
Match value:/foo
Pattern:*.ext

Context root mapping
http://localhost:8080/servlet4


Mapping match:CONTEXT_ROOT
Match value:
Pattern:

Default (fallback) mapping
http://localhost:8080/servlet4/doesnotexist


Mapping match:DEFAULT
Match value:/
Pattern:/

Exact mapping
http://localhost:8080/servlet4/exact


Mapping match:EXACT
Match value:/exact
Pattern:/exact
To test the implicit mapping (as per Servlet spec 12.2.1), the following JSP file was used:

<%
Mapping mapping = request.getMapping();

response.getWriter()
.append("Mapping match:")
.append(mapping.getMatchType().name())
.append("\n")
.append("Match value:")
.append(mapping.getMatchValue())
.append("\n")
.append("Pattern:")
.append(mapping.getPattern());
%>
This was however seen by Tomcat as a regular extension mapping:

Implicit mapping
http://localhost:8080/servlet4/page.jsp


Mapping match:EXTENSION
Match value:/page
Pattern:*.jsp
Implicit mappings are a little bit difficult to represent. Are they a mapping themselves, or is it just extra information? I.e. can you speak of an "implicit extension mapping" and an "implicit path mapping"?

Conclusion

At the moment it's unfortunately difficult to commit code to the Servlet RI (GlassFish), but Tomcat 9.0 M4 can be used to get an early glimpse of one of the new Servlet APIs. As the examples have shown, the new Mapping API now makes it trivial to find out via which mapping a Servlet was selected. The "implicit" mapping type however may still need some discussion.

Arjan Tijms

Java EE's mysterious message policy

$
0
0
Users of Java EE authentication (JASPIC) may have noticed that the initialize method of a SAM takes two parameters of type MessagePolicy. But what are these parameters used for? In this article we'll take a somewhat deeper look.

In practice, the overwhelming majority of SAMs only seem to use this MessagePolicy in one way; completely ignore it. As such, there aren't many if any examples available that demonstrate how these passed in policies should actually be enforced.

The JASPIC spec isn't quite clear about this either. It does seem to say in a somewhat cryptic way that the isMandatory method is an alias for the "javax.security.auth.message.MessagePolicy.isMandatory" entry in the MessageInfo map, and that the ProtectionPolicy of the TargetPolicy of the MessagePolicy must be ProtectionPolicy.AUTHENTICATE_SENDER and/or ProtectionPolicy.AUTHENTICATE_CONTENT.

Pretty much the only example we have in code that at least references the MessagePolicy type is within the Java EE reference implementation; GlassFish. Although GlassFish doesn't use JASPIC for the Servlet defined authentication mechanisms (FORM, BASIC, ...), it does uses JASPIC for the authentication mechanism protecting its build-in admin console. This is configured in domain.xml as follows:


<message-security-config auth-layer="HttpServlet">
<provider-config provider-type="server"
provider-id="GFConsoleAuthModule"
class-name="org.glassfish.admingui.common.security.AdminConsoleAuthModule">
<request-policy auth-source="sender"/&gt
<response-policy/&gt
<property name="loginPage" value="/login.jsf"/&gt
<property name="loginErrorPage" value="/loginError.jsf"/&gt
</provider-config>
</message-security-config>

Unfortunately, despite a minimal request policy being configured here, the actual implementation of AdminConsoleAuthModule does the same thing that basically all other SAMs do: ignore it.

For another potential hint, let's see what the RI actually does internally with the message policy before it passes it to a SAM. For this I started at the entry point of a SAM, when the runtime calls the validateRequest method of the encapsulating context. In order to make things readable for this article, I removed all alternative branches in the code (mostly permutations of client/server modules and new/old modules (new = jaspic, old = the GlassFish proprietary predecessor of JASPIC) and Servlet/SOAP). With those branches removed and flattening the code found in many helper methods and contained objects, it looks as follows:


// Check if the resource is secured and put as string in Map
isMandatory = !webSecMgr.permitAll(req);
if (isMandatory || calledFromAuthenticate) {
messageInfo.getMap().put(IS_MANDATORY, TRUE.toString());
}

// Get “true” / “false” string from map, convert it to Boolean and then to string again
String isMandatoryStr = messageInfo.getMap().get(IS_MANDATORY);
String authContextID = Boolean.valueOf(isMandatoryStr).toString();

// Convert once again to Boolean, and set to MANDATORY or OPTIONAL policy
messagePolicy = Boolean.valueOf(authContextID)?
new MessagePolicy[] { MANDATORY_POLICY, null } : // response policy always null
new MessagePolicy[] { OPTIONAL_POLICY, null }

IDEntry idEntry = configMap.get(“HttpServlet”).idMap.get(providerID);

// Set the definite request policy, but messagePolicy[0] is never null here
// for the “HttpServlet” layer
MessagePolicy requestPolicy = (messagePolicy[0] != null || messagePolicy[1] != null)?
messagePolicy[0] : // will always be chosen here
idEntry.requestPolicy; // the policy as parsed from domain.xml, always unused

Entry entry = new Entry(idEntry.moduleClassName, requestPolicy, idEntry.options);

// Pass the message policies into the SAM instance
ServerAuthModule sam = entry.newInstance();
sam.initialize(
entry.getRequestPolicy(),
entry.getResponsePolicy(), handler, map);

ModuleInfo moduleInfo = ModuleInfo(sam, map);

ServerAuthModule moduleObj = moduleInfo.getModule();
Map moduleMap = moduleInfo.getMap();

ServerAuthContext serverAuthContext = new GFServerAuthContext(moduleObj, moduleMap);

// Invoke the context, which on its turn will invoke the SAM we just initialized
AuthStatus authStatus = serverAuthContext.validateRequest(messageInfo, subject, null);

As can be seen, despite there being a path for setting the parsed request policy from domain.xml (the idEntry.requestPolicy), the code always chooses between one of two fixed policies; MANDATORY_POLICY or OPTIONAL_POLICY, depending on the same IS_MANDATORY value ("javax.security.auth.message.MessagePolicy.isMandatory") that is put in the message info map.

Those two fixed policies are set as static final variables as follows:


private static final MessagePolicy MANDATORY_POLICY =
getMessagePolicy(true);

private static final MessagePolicy OPTIONAL_POLICY =
getMessagePolicy(false);
Where the getMessagePolicy() method has the following relevant content (code branches that were never taken have been cut out again):

public static MessagePolicy getMessagePolicy (boolean mandatory) {

List<TargetPolicy> targetPolicies = new ArrayList<TargetPolicy>();

targetPolicies.add(new TargetPolicy(
null, // No Target
new ProtectionPolicy() {
public String getID() {
return ProtectionPolicy.AUTHENTICATE_SENDER;
}
})
);

return new MessagePolicy(
targetPolicies.toArray(new TargetPolicy[targetPolicies.size()]),
mandatory);
}

Conclusion

The conclusion seems to be, assuming that the RI code is as spec compliant as we can get, that MessagePolicy#isMandatory() is just an alternative for checking the message info map, while the TargetPolicy, Target and ProtectionPolicy are essentially useless for a Servlet Container Profile SAM, since at least for the RI they always have the same constant value. It has to be noted that if a SAM is registered programmatically, the entire initialization of the SAM is under the application's control and the behavior of the server doesn't apply.

Speculating, it might be the case that AUTHENTICATE_SENDER simply means "do what a SAM is supposed to do in validateRequest()" (e.g. authenticating callers), while the potential alternative or additional AUTHENTICATE_CONTENT means "do what a SAM is supposed to do in secureResponse()" (e.g. encrypting the response). If that interpretation would indeed be correct, one may see these message policies as standard switches (properties) for these two methods. E.g. a message policy with AUTHENTICATE_CONTENT and isMandatory() returning true would then mean that the SAM *must* encrypt the response. This latter thing however seems to be just as rare in practice as actually looking at the message policy is.

A quick glimpse at the SOAP Profile, and some of the implementation code in the RI, revealed that the entire message policy concept may have some more use over there. As JASPIC was originally designed with many potential other profiles in mind (e.g. for EJB, JMS, etc), it could also well be that the concept was designed for a future that just never came to be.

Arjan Tijms

The state of portable authentication in Java EE, mid 2016 update

$
0
0
In the beginning of this year and two months prior to that we looked at how well modern Java EE servers supported portable authentication (JASPIC) in Java EE. In this article we look at the current state of the union.

Originally the situation didn't looked that rosy, but since then things have been steadily improving. Since last time new versions of Payara, WildFly and Liberty have been released, while TomEE now also supports JASPIC. No new versions of Oracle's WebLogic and GlassFish were released. New tests have been added for registering a session with a custom principal and EJB propagation after register session.

The results of running the latest series of JASPIC tests are shown below:

Running the Java EE 7 samples JASPIC tests
ModuleTestPayara 4.1.1.163 snapshotWildFly 10.0.0Liberty 9 beta 2016.5TomEE 7.0.0
async-authenticationtestBasicAsync
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedPageNotLoggedin
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedPageLoggedin
Passed
Passed
Passed
Passed
basic-authenticationtestPublicPageLoggedin
Passed
Passed
Passed
Passed
basic-authenticationtestPublicPageNotLoggedin
Passed
Passed
Passed
Passed
basic-authenticationtestPublicAccessIsStateless
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedAccessIsStateless
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedAccessIsStateless2
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedThenPublicAccessIsStateless
Passed
Passed
Passed
Passed
custom-principaltestProtectedPageLoggedin
Passed
Passed
Passed
Passed
custom-principaltestPublicPageLoggedin
Passed
Passed
Passed
Passed
custom-principaltestPublicAccessIsStateless
Passed
Passed
Passed
Passed
custom-principaltestProtectedAccessIsStateless
Passed
Passed
Passed
Passed
custom-principaltestProtectedAccessIsStateless2
Passed
Passed
Passed
Passed
custom-principaltestProtectedThenPublicAccessIsStateless
Passed
Passed
Passed
Passed
dispatchingtestBasicForwardViaProtectedResource
Passed
Passed
Passed
Passed
dispatchingtestBasicForwardViaPublicResource
Passed
Passed
Passed
Passed
dispatchingtestBasicIncludeViaPublicResource
Passed
Passed
Passed
Passed
dispatching-jsf-cditestCDIForwardViaProtectedResource
Passed
Passed
Passed
Passed
dispatching-jsf-cditestCDIForwardViaPublicResource
Passed
Passed
Passed
Passed
dispatching-jsf-cditestCDIIncludeViaPublicResource
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFwithCDIForwardViaPublicResource
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFwithCDIForwardViaProtectedResource
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFwithCDIIncludeViaPublicResource
Failure
Failure
Failure
Passed
dispatching-jsf-cditestJSFForwardViaPublicResource
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFForwardViaProtectedResource
Passed
Passed
Passed
Passed
dispatching-jsf-cditestJSFIncludeViaPublicResource
Failure
Failure
Failure
Passed
ejb-propagationpublicServletCallingProtectedEJB
Passed
Passed
Passed
Passed
ejb-propagationprotectedServletCallingProtectedEJB
Passed
Passed
Passed
Passed
ejb-propagationpublicServletCallingPublicEJBThenLogout
Passed
Passed
Passed
Passed
ejb-propagationprotectedServletCallingPublicEJB
Passed
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeCDIFromSecureResponse
Passed
Passed
Failure
Passed
invoke-ejb-cdiprotectedInvokeCDIFromCleanSubject
Passed
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeCDIFromValidateRequest
Passed
Passed
Failure
Passed
invoke-ejb-cdipublicInvokeCDIFromSecureResponse
Passed
Passed
Failure
Passed
invoke-ejb-cdipublicInvokeCDIFromValidateRequest
Passed
Passed
Failure
Passed
invoke-ejb-cdipublicInvokeCDIFromCleanSubject
Passed
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeEJBFromSecureResponse
Passed
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeEJBFromCleanSubject
Passed
Passed
Passed
Passed
invoke-ejb-cdiprotectedInvokeEJBFromValidateRequest
Passed
Passed
Passed
Passed
invoke-ejb-cdipublicInvokeEJBFromSecureResponse
Passed
Passed
Passed
Passed
invoke-ejb-cdipublicInvokeEJBFromValidateRequest
Passed
Passed
Passed
Passed
invoke-ejb-cdipublicInvokeEJBFromCleanSubject
Passed
Passed
Passed
Passed
jacc-propagationcallingJACCWhenAuthenticated
Passed
Failure
Failure
Failure
jacc-propagationcallingJACCWhenAuthenticated
Passed
Failure
Failure
Failure
jacc-propagationcallingJACCWhenNotAuthenticated
Passed
Passed
Failure
Failure
lifecycletestBasicSAMMethodsCalled
Passed
Passed
Passed
Passed
lifecycletestLogout
Passed
Passed
Passed
Passed
register-sessiontestRemembersSessionEJB
Passed
Failure
Passed
Passed
register-sessiontestJoinSessionIsOptional
Passed
Passed
Failure
Passed
register-sessiontestRemembersSession
Passed
Passed
Passed
Passed
register-sessiontestRemembersSessionEJB
Passed
Failure
Passed
Passed
register-sessiontestJoinSessionIsOptional
Passed
Passed
Failure
Passed
register-sessiontestRemembersSession
Passed
Passed
Passed
Passed
status-codestest404inResponse
Passed
Passed
Passed
Passed
status-codestest404inResponse
Passed
Passed
Passed
Passed
wrappingtestResponseWrapping
Passed
Passed
Passed
Passed
wrappingtestRequestWrapping
Passed
Passed
Passed
Passed

Not directly shown in the table, but one of the biggest changes is that Liberty 9 beta 2016.5 no longer needs JASPIC to be activated in a problematic and proprietary way. Historically Liberty was one of the most problematic servers in this area. It originally required all users and groups to be made known to a Liberty specific artefact called a user registry (a kind of identity store). This requirement was later relaxed such that only groups had to be defined, but since group to role mapping was also mandatory, this stil meant defining the same group at least 3 times if no actual group mapping was needed.

In Liberty 9 beta 2016.5 all this overhead is now completely gone, and just like GlassFish and WebLogic, JASPIC just works without any activation whatsoever (with a caveat for GlassFish that by default it does require group to role mapping). One thing to watch out for is that if you do need group to role mapping, you seemingly can't just use Liberty's role mapping file (ibm-application-bnd.xml), but also need to define the above mentioned user registry again. All other servers (that feature a role mapper) allow the mapping of groups set by a JASPIC SAM via only a single XML file. When asked about this, the Liberty lead mentioned that this is due to backwards compatibility, which does make sense. It's also not such a bad thing; if you want to use the proprietary group to role mapping feature it's only a relatively small extra step to also activate a proprietary artefact such as the user registry.

As far as JASPIC functionality goes, Liberty keeps failing the CDI related tests and the JACC ones. The JACC ones are a clear spec violation (confirmed by the JACC and JASPIC spec lead), but since it concerns a requirement that was never enforced (namely, JACC has to be available and used by default) it's likely far from trivial to just fix this. Liberty also fails a test where the authenticated user is changed during the same HTTP session. This however clashes with Liberty's protection against a session fixation attack, which for instance happens when a user logs out and without resetting the http session (specifically changing its ID) a new user logs in again. This protection can be disabled by putting <httpSession securityIntegrationEnabled="false"/&gt in server.xml.

As mentioned above, TomEE is new to JASPIC scene, but what an entrance it makes! In it's very first release it passed all JASPIC tests, safe the JACC ones. TomEE (as not a full Java EE 7 certified server) is however not required to support JACC at all, let alone out of the box. Since TomEE does actually support JACC it may be possible to have it pass these tests as well. Right from the start TomEE also doesn't require any explicit activation of JASPIC. It just works out of the box.

JBoss/WildFly, while still having a very good JASPIC implementation fell a tiny bit behind. It still doesn't pass all JACC tests, even though JACC is in fact available by default (a bug prevents roles to be propagated correctly). Additionally, a new bug was found that prevents roles being propagated to EJB beans when the remember session feature is used. JBoss also still requires the dummy-like marker file (jboss-web.xml) in an archive to activate JASPIC. Even though such marker file is only a small nuisance compared to having to modify the server itself, it does make JBoss the sole server now that requires such activation at all (but as mentioned above, GlassFish/Payara requires a proprietary group to role mapping file to be present).

Payara also suffered from a newly discovered bug, this one involving the combination of the remember session feature and a custom principal. This was however quickly fixed in the 4.1.1.163 branch and Payara remains one of the strongest JASPIC implementations. There's essentially only one minor failure involving a not too common case of including a JSF resource from within a SAM.

Conclusion

7 years after portable authentication was introduced in Java EE 6 and 3 years after its revision in Java EE 7, JASPIC implementations are now finally getting really compliant. There's a residu of bugs in the various implementations that still need to be fixed, and a few inconveniences to take away in some servers (JBoss' jboss-web.xml and GlassFish/Payara's glassfish-web.xml), but overal things are starting to look very good.

The one big exception remains WebLogic 12.2.1, which currently doesn't work at all after a major bug was introduced in that version that prevents basic authentication to work correctly (effectively a blocker bug that makes running all other tests rather moot)

Arjan Tijms

Simplified custom authorization rules in Java EE

$
0
0
In a previous article we looked at implementing a Java EE authorization module using the JACC specification. This module implemented the default authorization rules as specified by the JACC-, Servlet- and EJB specifications. In this article we go beyond that default algorithm and take a look at providing our own custom authorization rules.

In order to implement custom rules, one would traditionally ship an entire JACC provider with factory, configuration and policy. Not only is this a lot of code (JACC doesn't have any code that can be reused, for the smallest change everything needs to be implemented from scratch), it's also problematic that a JACC provider is global for the entire application server, while authorization rules are almost always specific for an individual application. Even when you adhere to the best practice of using one application per server, it's still quite a hassle to re-install the JACC provider after every little change separately from the application.

For this article we're therefor going to employ a different approach; use CDI to delegate from a single JACC provider that's installed once, to an application specific CDI bean. Incidentally this is largely the same thing Soteria/JSR 375 is doing for authentication mechanisms, which the key difference that the Java EE authentication SPI -does- allow authentication modules to be installed per application.

For the actual custom authorization rule we took inspiration from a rather interesting question and answer on StackOverflow:

Is it possible to determine group membership of a user on demand instead of when logging in via a ServerAuthModule (JASPIC)?

As it appears, the answer to this question is yes ;)

In order to come to a solution for the above stated problem we first took the original JACC provider from the previous article and refactored it a little. The permissions that were previously put in the intermediate base class TestPolicyConfigurationPermissions were factored out to a separate struct like class:


public class SecurityConstraints {

private Permissions excludedPermissions = new Permissions();
private Permissions uncheckedPermissions = new Permissions();
private Map<String, Permissions> perRolePermissions = new HashMap<String, Permissions>();

// + getters/setters
Furthermore a new class was introduced that holds the caller (name) principal, the (mapped) roles and the raw set of unmapped principals (which are often server specific):

public class Caller {

private Principal callerPrincipal;
private List<String> roles;
private List<Principal> unmappedPrincipals;

// + getters/setters
Next we define an interface for the application to implement. Our JACC provider will call this at certain points during the authorization process:

public interface AuthorizationMechanism {

default Boolean preAuthenticatePreAuthorize(Permission requestedPermission, SecurityConstraints securityConstraints) {
return null;
}

default Boolean preAuthenticatePreAuthorizeByRole(Permission requestedPermission, SecurityConstraints securityConstraints) {
return null;
}

default Boolean postAuthenticatePreAuthorize(Permission requestedPermission, Caller caller, SecurityConstraints securityConstraints) {
return null;
}

default Boolean postAuthenticatePreAuthorizeByRole(Permission requestedPermission, Caller caller, SecurityConstraints securityConstraints) {
return null;
}
}
As can be seen we distinguish for authorization decisions before authentication has taken place and thereafter, and for those at the start of an authorization decision and right before it comes time to check for role based permissions. The difference between those last two moments is that for the latter the tests for excluded permissions (those granted to no one) and unchecked (permissions granted to everyone) have already been performed. (Note that methods have been used for now, but perhaps events are the better solution here)

With these artefacts in place we can now modify the JACC Policy class to request a bean via CDI that implements the AuthorizationMechanism interface, and if it exists call one of the appropriate methods. The following shows an excerpt of this:


boolean postAuthenticate = domain.getPrincipals().length > 0;

AuthorizationMechanism mechanism = getBeanReferenceExtra(AuthorizationMechanism.class);
Caller caller = null;

if (postAuthenticate) {
caller = new Caller(
roleMapper.getCallerPrincipalFromPrincipals(currentUserPrincipals),
roleMapper.getMappedRolesFromPrincipals(currentUserPrincipals),
currentUserPrincipals);
}

if (mechanism != null) {
Boolean authorizationOutcome = postAuthenticate?
mechanism.postAuthenticatePreAuthorize(requestedPermission, caller, securityConstraints) :
mechanism.preAuthenticatePreAuthorize(requestedPermission, securityConstraints);

if (authorizationOutcome != null) {
return authorizationOutcome;
}
}

In the code above getBeanReferenceExtra uses CDI to fetch a bean of type AuthorizationMechanism. This method works around a bug in Payara where the so-called component namespaces aren't being set. This bug is pretty much the same as also existed for calling a JASPIC SAM. If the mechanism is not null, then depending on whether authentication has already happened or not either the postAuthenticatePreAuthorize or the preAuthenticatePreAuthorize is called.

The JACC Policy doesn't tell us explicitly if the call is before or after authentication, but we can deduct this by looking at the passed-in principals. The assumption is that before authentication there are no principals at all, and after authentication there's at least one (if there was no actual authentication being done, the so-called "unauthenticated caller principal" is added).

For further details see the full source code.

With the JACC provider in place we can now create a Java EE web application that takes advantage of it. We'll start with a custom JSR 375 IdentityStore that only authenticates a single user named "test" and doesn't return any groups:


@RequestScoped
public class CustomIdentityStore implements IdentityStore {

public CredentialValidationResult validate(UsernamePasswordCredential usernamePasswordCredential) {

if (usernamePasswordCredential.getCaller().equals("test") &&
usernamePasswordCredential.getPassword().compareTo("secret1")) {

return new CredentialValidationResult(
new CallerPrincipal("test"),
null // no static groups, dynamically handled via authorization mechanism
);
}

return INVALID_RESULT;
}

}
We also add a custom JSR 375 HttpAuthenticationMechanism, one that's just used for testing purposes:

@RequestScoped
public class CustomAuthenticationMechanism implements HttpAuthenticationMechanism {

@Inject
private IdentityStore identityStore;

@Override
public AuthStatus validateRequest(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws AuthException {

if (request.getParameter("name") != null && request.getParameter("password") != null) {

CredentialValidationResult result = identityStore.validate(
new UsernamePasswordCredential(request.getParameter("name"), request.getParameter("password")));

if (result.getStatus() == VALID) {
return httpMessageContext.notifyContainerAboutLogin(
result.getCallerPrincipal(), result.getCallerGroups());
} else {
throw new AuthException("Login failed");
}
}

return httpMessageContext.doNothing();
}

}
Note that we could have omitted both the custom identity store and custom authentication mechanism and instead configured the default embedded store and the default BASIC authentication mechanism, but now we more clearly see what's exactly happening in the authentication process. Also note that the HttpAuthenticationMechanism is a CDI based HTTP specific variant of the ServerAuthModule that was mentioned in the SO question cited above.

Let's now finally look at our custom authorization rule, which basically looks as follows:


@ApplicationScoped
public class CustomAuthorizationMechanism implements AuthorizationMechanism {

@Override
public Boolean postAuthenticatePreAuthorizeByRole(Permission requestedPermission, Caller caller, SecurityConstraints securityConstraints) {

return getRequiredRoles(securityConstraints.getPerRolePermissions(), requestedPermission)
.stream()
.anyMatch(role -> isInRole(caller.getCallerPrincipal().getName(), role));
}
}
What's happening here is that our custom code is being asked to authorize the caller for some requested permission. Such permission can e.g. be a WebResourcePermission for a given protected path like /foo/bar.

In order to do the on demand membership check as was asked for in the SO question we start with using the getRequiredRoles method and the collectedSecurityConstraints to obtain a list of roles that are required for the requested permission. We then look if the current caller is in any of those roles using the isInRole method. This method can do whatever backend lookup is needed, but for an example application we'll mock it using a simple map where we put caller "test" in roles "foo", "bar" and "kaz".

For completeness, the getRequiredRoles method gets the roles that are required for a requested permission as follows:


return perRolePermissions
.entrySet().stream()
.filter(entry -> entry.getValue().implies(requestedPermission))
.map(e -> e.getKey())
.collect(toList());
In order to test if the authorization rule works we add a protected Servlet as follows:

@DeclareRoles({ "foo", "bar", "kaz" })
@WebServlet("/protected/servlet")
@ServletSecurity(@HttpConstraint(rolesAllowed = "foo"))
public class ProtectedServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

response.getWriter().write("This is a protected servlet \n");

String webName = null;
if (request.getUserPrincipal() != null) {
webName = request.getUserPrincipal().getName();
}

response.getWriter().write("web username: " + webName + "\n");

response.getWriter().write("web user has role \"foo\": " + request.isUserInRole("foo") + "\n");
response.getWriter().write("web user has role \"bar\": " + request.isUserInRole("bar") + "\n");
response.getWriter().write("web user has role \"kaz\": " + request.isUserInRole("kaz") + "\n");
}

}
The Servlet shown here is protected by the role "foo", so with the above given IdentityStore which doesn't return any groups/roles for our caller "test", we would normally not be able to access this Servlet. Yet, with the custom authorization rule in place we're able to access this Servlet just fine when authenticating as user "test".

Next we added a preAuthenticatePreAuthorize method to our authorization mechanism with some logging and also added logging to our existing postAuthenticatePreAuthorizeByRole method. We then deployed the application as "custom-authorization" to Payara 4.1.1.162 and requested http://localhost:8080/custom-authorization/protected/servlet?name=test&password=secret1. This resulted in the following log entries:


preAuthenticatePreAuthorize called. Requested permission: ("javax.security.jacc.WebUserDataPermission""/protected/servlet""GET")
preAuthenticatePreAuthorize called. Requested permission: ("javax.security.jacc.WebResourcePermission""/protected/servlet""GET")

validateRequest called. Authentication mandatory: true

postAuthenticatePreAuthorizeByRole called. Requested permission: ("javax.security.jacc.WebResourcePermission""/protected/servlet""GET")

postAuthenticatePreAuthorizeByRole called. Requested permission: ("javax.security.jacc.WebRoleRefPermission""org.omnifaces.authorization.ProtectedServlet""foo")
postAuthenticatePreAuthorizeByRole called. Requested permission: ("javax.security.jacc.WebRoleRefPermission""org.omnifaces.authorization.ProtectedServlet""bar")
postAuthenticatePreAuthorizeByRole called. Requested permission: ("javax.security.jacc.WebRoleRefPermission""org.omnifaces.authorization.ProtectedServlet""kaz")
What we see happening here is that our authorization mechanism is initially called twice before authentication. First to see if the request can be aborted early by checking if the protocol (http/https) is allowed, and secondly to see if the resource is allowed to be accessed publicly. If the resource is allowed to be accessed publicly, authentication is still being asked for, but it's not mandatory then.

For the request to "/protected/servlet" authentication is mandatory as shown above. Since authentication is thus mandatory, our authorization mechanism is called again after authentication for the same requested WebResourcePermission permission, but this time the caller data corresponding to the authenticated identity is also available. Our method will return "true" here, since ("javax.security.jacc.WebResourcePermission""/protected/servlet""GET") will turn out to require the role "foo", and our mock "isInRole" method will return "true" for caller "test" and role "foo".

We therefor continue to our requested resource, which means the servlet will be invoked.

Interesting to note here is that HttpServletRequest#isUserInRole is not implemented internally by checking a simple list of roles, but by calling our authorization module with a requested permission ("javax.security.jacc.WebRoleRefPermission""org.omnifaces.authorization.ProtectedServlet""[role name]"). The three isUserInRole calls that the servlet shown above does therefor show up in the log as three calls to our authorization mechanism, each for a different role.

Also interesting to note is that our authorization mechanism handles a requested permission to access "/protected/servlet" and a requested permission for isUserInRole("foo") completely identical. If necessary the authorization mechanism can of course inspect the requested permission, but for this use case that wasn't necessary.

To contrast the call to the protected servlet, let's also take a quick look at the log entries resulting from a call to a public servlet that's otherwise identical to the protected one:


preAuthenticatePreAuthorize called. Requested permission: ("javax.security.jacc.WebUserDataPermission""/public/servlet""GET")
preAuthenticatePreAuthorize called. Requested permission: ("javax.security.jacc.WebResourcePermission""/public/servlet""GET")

validateRequest called. Authentication mandatory: false

postAuthenticatePreAuthorizeByRole called. Requested permission: ("javax.security.jacc.WebRoleRefPermission""org.omnifaces.authorization.PublicServlet""foo")
postAuthenticatePreAuthorizeByRole called. Requested permission: ("javax.security.jacc.WebRoleRefPermission""org.omnifaces.authorization.PublicServlet""bar")
postAuthenticatePreAuthorizeByRole called. Requested permission: ("javax.security.jacc.WebRoleRefPermission""org.omnifaces.authorization.PublicServlet""kaz")
What we see here is that our authorization mechanism is initially called twice again, but since the default authorization algorithm will grant access to the anonymous caller the subsequent authentication is not mandatory and our authorization mechanism will also not be called a second time for the same resource permission.

For more details see the full source code of the example application.

Conclusion

We've seen that custom authorization rules allow us to do things that are normally not thought possible using Java EE security. Java EE's security model is clearly much more advanced than just the basic ability to check for roles, but much of its power has likely been untapped by many.

The reason for this is the relative obscurity of the JACC specification, the difficulty to install a provider and the very large amount of work required for even the smallest amount of custom authorization logic. The approach presented in this article allows us to re-use an existing JACC provider and provide custom authorization logic with a minimal amount of code.

What we presented here is only a prototype, but it may serve as a basis for authorization in the Java EE Security API (JSR 375).

Arjan Tijms


Custom authorization rules on IBM Liberty

$
0
0
Last month we presented a way how a Java EE application can provide custom rules for authorization. The code shown in that article was developed and tested using Payara. We're now going to look at how the code can be used on some other servers, starting with IBM's Liberty.

Liberty has a highly modularised architecture and features a rather amazing way by which and end user can compose the runtime. By means of its server.xml file, a Liberty user can add or remove nearly every individual feature that Liberty has independently. The Liberty core system keeps track of the dependencies of each module representing such feature and adds or removes its dependencies accordingly (in a way not quite unlike what a tool like Maven does at build time).

All this power does come at some price. For Liberty the JACC provider which is needed to implement the logic behind the custom authorization rules has to be turned into a Liberty specific module (called a user feature), which is quite a bit more work than needed for other servers (even the ones that are also modular).

Summarised we have to:

  • Create an OSGi bundle
  • Add our JACC provider jar to this bundle
  • Implement a Liberty specific service that returns the policy and factory instances from our provider
  • Make sure we have the right imports and exports
  • Create a Liberty Feature that references the previously created bundle and provides the right exports
  • Installing the feature in Liberty

IBM provides documentation on how to install a JACC provider within Liberty, but unfortunately the documentation is not entirely clear, and even less fortunately it's not fully correct.

As in some of the other documents from IBM the JACC installation has some very terse instructions. They may be clear if you're a rather experienced Liberty and/or OSGi user, but if you're not a sentence like the following might be a bit puzzling:

Package the component into an OSGi bundle that is part of your user feature, along with your JACC provider.
The above is more a summary of what we have to do, not how to actually do it. We look at the how in some more detail below:

Create an OSGi bundle

Luckily IBM also has instructions for a "hello world" user feature, which are much more complete and easier to follow. Not so lucky was that after creating an "OSGI Bundle Project" as indicated by those instructions I got a compile error right away in the project. For some unfathomable reason the package org.osgi.framework could not be found. Eventually it appeared that next to a target runtime (which was set to the installed Liberty server), Eclipse also has the notion of a target platform. The first one normally provides the packages a project compiles against, but in an OSGi project things are never that simple. The target platform changes automatically when you set the target runtime for your project, even though for former is global for your entire workspace and the latter is per project.

The target platform can be set in Eclipse in Preferences -> Plug-in Development -> Target Platform. See the screenshot below:

Switching to "Running platform" solved the compile error for org.osgi.framework, but the IBM specific bundles couldn't be resolved then. Switching to "Liberty beta 2016.8 with SPI" solved the problem, but later on I could switch back to "Liberty beta 2016.8" without the compile error coming back. Eclipse sometimes works in mysterious ways.

Add our JACC provider jar to this bundle

Not mentioned anywhere in the IBM documentation, but the existing JACC provider jar had to be copied into the BundleContent folder of the OSGi bundle project. The Eclipse manifest editor (runtime tab -> classpath pane) for some reason doesn't let you pick from this location, but it can be easily added directly to the MANIFEST.FM file by adding the following to it:


Bundle-ClassPath: .,
cdi-jacc-provider-0.1-SNAPSHOT.jar
After the JACC provider jar has been added in this way, the manifest editor shows the jar, but it will not have been added to the classpath of the project itself. This has to be done separately by going to project -> properties -> Java Build Path -> Libraries and adding the jar there too. See the screenshot below:

Implement a Liberty specific service that returns the policy and factory instances from our provider

Contrary to all other servers, Liberty requires an amount of Liberty specific code in the module. The above mentioned instructions give an example of this, but unfortunately that code for a required service seemed to be rather faulty. Among others several imports were missing, the "getPolicyConfigurationFactory" method name was wrong (should be "getPolicyConfigFactory"), the return type of that same method was wrong (instead of "Policy" it should be "PolicyConfigurationFactory", then there's an active method that used a variable called "configprops" that's not defined anywhere, etc.

Additionally, the service uses the @Component annotation, which is said to generally make things easier, but I wasn't able to use it. After importing the right package for it, Liberty kept logging the following error when starting up:

[ERROR ] CWWKE0702E: Could not resolve module: JaccBundle [250] Unresolved requirement: Import-Package: org.osgi.service.component.annotations; version="1.3.0"

Being unable to resolve this, I removed the annotation and implemented a traditional Activator instead. The code for both the service and the activator is shown below:

Service:


package jaccbundle;

import static java.lang.System.setProperty;
import static java.lang.Thread.currentThread;

import java.security.Policy;

import javax.security.jacc.PolicyConfigurationFactory;

import org.omnifaces.jaccprovider.jacc.policy.DefaultPolicy;

import com.ibm.wsspi.security.authorization.jacc.ProviderService;

public class MyJaccProviderService implements ProviderService {

@Override
public Policy getPolicy() {
return new DefaultPolicy();
}

@Override
public PolicyConfigurationFactory getPolicyConfigFactory() {

ClassLoader originalContextClassloader =
currentThread().getContextClassLoader();
try {
currentThread()
.setContextClassLoader(
this.getClass().getClassLoader());

setProperty(
"javax.security.jacc.PolicyConfigurationFactory.provider",
"org.omnifaces.jaccprovider.jacc.configuration.TestPolicyConfigurationFactory");

return PolicyConfigurationFactory.getPolicyConfigurationFactory();
} catch (Exception e) {
return null;
} finally {
Thread.currentThread()
.setContextClassLoader(
originalContextClassloader);
}
}
}

Activator


package jaccbundle;

import static org.osgi.framework.Constants.SERVICE_PID;

import java.util.Hashtable;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

import com.ibm.wsspi.security.authorization.jacc.ProviderService;

public class Activator implements BundleActivator {

private static final String CONFIG_PID = "jaccBundle";
private ServiceRegistration<ProviderService> jaccProviderService;

public void start(BundleContext context) throws Exception {
jaccProviderService = context.registerService(
ProviderService.class,
new MyJaccProviderService(),
getDefaults());
}

public void stop(BundleContext context) throws Exception {
if (jaccProviderService != null) {
jaccProviderService.unregister();
jaccProviderService = null;
}
}

Hashtable<String, ?> getDefaults() {
Hashtable<String, String> defaults = new Hashtable<>();
defaults.put(SERVICE_PID, CONFIG_PID);
return defaults;
}

}

Make sure we have the right imports and exports

The Eclipse manifest editor offers a handy "Analyze code and add dependencies to the MANIFEST.FM" feature, but like the matter duplicator it doesn't work and has never worked. They can be added manually though. In the editor it's Dependencies -> Imported packages for the imports, and Runtime -> Exported packages for the exports. See below:

After some trial and error the MANIFEST.FM eventually looked like this:


Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: JaccBundle
Bundle-SymbolicName: JaccBundle
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: jaccbundle.Activator
Bundle-ClassPath: .,
cdi-jacc-provider-0.1-SNAPSHOT.jar
Import-Package: com.ibm.wsspi.security.authorization.jacc;version="1.0.0",
javax.enterprise.context;version="1.1.0",
javax.enterprise.context.spi;version="1.1.0",
javax.enterprise.inject;version="1.1.0",
javax.enterprise.inject.spi;version="1.1.0",
javax.inject;version="1.0.0",
javax.naming,
javax.security.auth,
javax.security.jacc;version="1.5.0",
org.osgi.framework
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Export-Package: jaccbundle,
org.omnifaces.jaccprovider.cdi,
org.omnifaces.jaccprovider.jacc

Create a Liberty Feature that references the previously created bundle and provides the right exports

After having created the Liberty Feature project using the IBM instruction for the hello world feature, there's relatively little to be done here. We do have to add the exports that we already exported from the bundle again here.

This can be done via the editor for the one and only file in our feature project called SUBSYSTEM.FM:

The raw file will then look as follows:

Subsystem-ManifestVersion: 1.0
IBM-Feature-Version: 2
IBM-ShortName: JaccFeature
Subsystem-SymbolicName: JaccFeature;visibility:=public
Subsystem-Version: 1.0.0.qualifier
Subsystem-Type: osgi.subsystem.feature
Subsystem-Content: JaccBundle;version="1.0.0"
Manifest-Version: 1.0
IBM-API-Package: org.omnifaces.jaccprovider.cdi,
org.omnifaces.jaccprovider.jacc
The IBM JACC installation instructions mentioned one other point here:
Ensure that your feature includes the OSGi subsystem content: com.ibm.ws.javaee.jacc.1.5; location:="dev/api/spec/".
I could however not get this to work. Adding it to SUBSYSTEM.FM as follows:

Subsystem-Content: JaccBundle;version="1.0.0",com.ibm.ws.javaee.jacc.1.5;location:="dev/api/spec/"
Resulted in the following error when starting Liberty:

Bundle location:="dev/api/spec/" cannot be
resolved
Adding it as:

Subsystem-Content: JaccBundle;version="1.0.0",com.ibm.ws.javaee.jacc.1.5
Yielded the following error:

[ERROR ] CWWKE0702E: Could not resolve module: com.ibm.ws.javaee.jacc.1.5 [251]
Another singleton bundle selected: osgi.identity; osgi.identity="com.ibm.ws.javaee.jacc.1.5"; type="osgi.bundle"; version:Version="1.0.13.20160722-1732"; singleton:="true"
Without this directive the JACC provider already worked as expected, so I just left it out. It's intended use is somewhat puzzling though.

The workspace with all artefacts combined for the two required projects looks as follows:

Installing the feature in Liberty

As explained in the hello world instructions by IBM, the feature with the embedded bundle with the embedded JACC provider jar can be installed via the Feature project by right clicking on it in Eclipse and selecting "Install Feature". After that is done, the final step is to add the new feature to Liberty's server.xml file, for which there again is a graphical editor in Eclipse:

The raw file look as follows:


<server description="Liberty beta">

<featureManager>
<feature>javaee-7.0</feature>
<feature>localConnector-1.0</feature>
<feature>usr:JaccFeature</feature>
</featureManager>

<httpEndpoint httpPort="8080" httpsPort="9443" id="defaultHttpEndpoint"/>

<webContainer deferServletLoad="false"/>
<ejbContainer startEJBsAtAppStart="true"/>

<applicationManager autoExpand="true"/>
<applicationMonitor updateTrigger="mbean"/>

</server>

After this we can finally run a web application to test things, and it indeed seems to work as expected!

One thing to keep in mind is that Liberty initialises the CDI request scope rather late (after authentication has been done). For some of the calls to our custom JACC provider this is way too late. Fortunately, CDI *does* work, but only for scopes that don't depend on the current request (like the application scope).

The authorization mechanism as demonstrated in the previous article most naturally uses the application scope anyway, so here that's no problem. For the brave, the request scope for CDI can forcefully and in a hacky way be activated earlier (e.g. in a JASPIC SAM) as follows:


Object weldInitialListener = request.getServletContext().getAttribute("org.jboss.weld.servlet.WeldInitialListener");
ServletRequestEvent event = new ServletRequestEvent(request.getServletContext(), request);

ELProcessor elProcessor = new ELProcessor();
elProcessor.defineBean("weldInitialListener", weldInitialListener);
elProcessor.defineBean("event", event);
elProcessor.eval("weldInitialListener.requestInitialized(event)");
Note again that this is a hack, and as such not guaranteed to work without any problems or keep working on newer versions of Liberty. It was only briefly tested on Liberty Beta 2016.8

Conclusion

Installing a JACC provider on Liberty is a lot of work. The vendor documentation is not clear on this and even contains errors. After a user feature has been created it's relatively easy though to add it to Liberty. Publishing it to a repository (not discussed in the article) would make it even easier to use the JACC provider on other instances of Liberty.

The amount of work that's required and the need to dive into vendor specific documentation could largely be eliminated by having a Java EE standard way to add a JACC provider from within an application (like what is currently possible for JASPIC SAMs). Hopefully a JACC MR will consider this.

Regardless, with the JACC provider installed once Liberty users can from then on easily add custom authorization rules to their applications. Care should be taken though that the JACC provider is just a POC. It shows great promise, but has not been extensively tested yet.

Arjan Tijms

The state of portable authentication in Java EE, end 2016 update

$
0
0
In the beginningand middle of this year we looked at how well modern Java EE servers supported portable authentication (JASPIC) in Java EE. As the end of 2016 approaches we take a third look to see how things are progressing.

Since our last time new versions of all servers have been released. Payara went from 163-beta to 164, WildFly went from 10.0 to 10.1, Liberty beta went from 2016-5 to 2016-11, WebLogic went from 12.2.1 to 12.2.1.2 and TomEE went from 7.0 to 7.0.2. We also added a new server, namely Tomcat. Tomcat was indirectly already tested via TomEE, but given the importance of standalone Tomcat we decided to put this one in explicitly. Do note that Tomcat is not a full or web profile Java EE server, so the integration tests for technologies it doesn't support (like JSF, CDI, etc) are simply omitted.

Tests were added for request.authenticate, an injected CDI request, the servlet path after a forward, isMandatory in a SAM, and finally for a SAM request to be seen by a Filter. For the first time there was also a test removed, namely including a JSF based resource from a SAM. This fails on many servers but the failure appeared to be a general JSF failure unrelated to JASPIC and/or its integration with the Java EE environment.

The results of running the latest series of JASPIC tests are shown below:

Running the Java EE 7 samples JASPIC tests
ModuleTestPayara 164WildFly 10.1Liberty 2016-11Weblogic 12.2.1.2TomEE 7.0.2Tomcat 8.5.6
async-authenticationtestBasicAsync
Passed
Passed
Passed
Passed
Passed
-
basic-authenticationtestProtectedPageNotLoggedin
Passed
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedPageLoggedin
Passed
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestPublicPageLoggedin
Passed
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestPublicPageNotLoggedin
Passed
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestPublicAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedAccessIsStateless2
Passed
Passed
Passed
Passed
Passed
Passed
basic-authenticationtestProtectedThenPublicAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
custom-principaltestProtectedPageLoggedin
Passed
Passed
Passed
Failure
Passed
Passed
custom-principaltestPublicPageLoggedin
Passed
Passed
Passed
Failure
Passed
Passed
custom-principaltestPublicAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
custom-principaltestProtectedAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
custom-principaltestProtectedAccessIsStateless2
Passed
Passed
Passed
Passed
Passed
Passed
custom-principaltestProtectedThenPublicAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
dispatchingtestBasicForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatchingtestBasicForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatchingtestBasicIncludeViaPublicResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cditestCDIForwardWithRequestProtected
Passed
Passed
Passed
Passed
Passed
-
dispatching-jsf-cditestCDIForwardWithRequestInjectPublic
Passed
Passed
Passed
Passed
Failure
-
dispatching-jsf-cditestCDIForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
-
dispatching-jsf-cditestCDIForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
-
dispatching-jsf-cditestCDIForwardWithRequestPublic
Passed
Passed
Passed
Passed
Passed
-
dispatching-jsf-cditestCDIForwardWithRequestInjectProtected
Passed
Passed
Passed
Passed
Failure
-
dispatching-jsf-cditestCDIIncludeViaPublicResource
Passed
Passed
Passed
Passed
Passed
-
dispatching-jsf-cditestJSFwithCDIForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
-
dispatching-jsf-cditestJSFwithCDIForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
-
dispatching-jsf-cditestJSFForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
-
dispatching-jsf-cditestJSFForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
-
ejb-propagationpublicServletCallingProtectedEJB
Passed
Passed
Passed
Failure
Passed
-
ejb-propagationprotectedServletCallingProtectedEJB
Passed
Passed
Passed
Failure
Passed
-
ejb-propagationpublicServletCallingPublicEJBThenLogout
Passed
Passed
Passed
Passed
Passed
-
ejb-propagationprotectedServletCallingPublicEJB
Passed
Passed
Passed
Passed
Passed
-
ejb-register-sessiontestRemembersSession
Passed
Passed
Passed
Failure
Passed
-
ejb-register-sessiontestRemembersSession
Passed
Passed
Passed
Failure
Passed
-
invoke-ejb-cdiprotectedInvokeCDIFromSecureResponse
Passed
Passed
Failure
Failure
Passed
-
invoke-ejb-cdiprotectedInvokeCDIFromCleanSubject
Passed
Passed
Passed
Passed
Passed
-
invoke-ejb-cdiprotectedInvokeCDIFromValidateRequest
Passed
Passed
Failure
Failure
Passed
-
invoke-ejb-cdipublicInvokeCDIUseInjectedRequestFromValidateRequest
Passed
Passed
Failure
Failure
Passed
-
invoke-ejb-cdipublicInvokeCDIFromSecureResponse
Passed
Passed
Failure
Failure
Passed
-
invoke-ejb-cdipublicInvokeCDIFromValidateRequest
Passed
Passed
Failure
Failure
Passed
-
invoke-ejb-cdipublicInvokeCDIUseInjectedRequestFromCleanSubject
Passed
Passed
Passed
Passed
Passed
-
invoke-ejb-cdipublicInvokeCDIUseInjectedRequestFromSecureResponse
Passed
Passed
Failure
Failure
Passed
-
invoke-ejb-cdipublicInvokeCDIFromCleanSubject
Passed
Passed
Passed
Passed
Passed
-
invoke-ejb-cdiprotectedInvokeEJBFromSecureResponse
Passed
Passed
Passed
Passed
Passed
-
invoke-ejb-cdiprotectedInvokeEJBFromCleanSubject
Passed
Passed
Passed
Passed
Passed
-
invoke-ejb-cdiprotectedInvokeEJBFromValidateRequest
Passed
Passed
Passed
Passed
Passed
-
invoke-ejb-cdipublicInvokeEJBFromSecureResponse
Passed
Passed
Passed
Passed
Passed
-
invoke-ejb-cdipublicInvokeEJBFromValidateRequest
Passed
Passed
Passed
Passed
Passed
-
invoke-ejb-cdipublicInvokeEJBFromCleanSubject
Passed
Passed
Passed
Passed
Passed
-
jacc-propagationcallingJACCWhenAuthenticated
Passed
Passed
Failure
Failure
Failure
-
jacc-propagationcallingJACCWhenAuthenticated
Passed
Passed
Failure
Failure
Failure
-
jacc-propagationcallingJACCWhenNotAuthenticated
Passed
Passed
Failure
Failure
Failure
-
lifecycletestBasicSAMMethodsCalled
Passed
Passed
Passed
Passed
Passed
Passed
lifecycletestLogout
Passed
Passed
Passed
Passed
Passed
Passed
lifecycletestProtectedIsMandatory
Passed
Passed
Passed
Passed
Passed
Passed
lifecycletestPublicIsNonMandatory
Passed
Passed
Passed
Passed
Passed
Passed
programmatic-authenticationtestAuthenticateFailFirstTwice
Passed
Passed
Passed
Passed
Passed
Passed
programmatic-authenticationtestAuthenticate
Passed
Passed
Passed
Passed
Passed
Passed
programmatic-authenticationtestAuthenticateFailFirstOnce
Passed
Passed
Passed
Passed
Passed
Passed
register-sessiontestJoinSessionIsOptional
Passed
Passed
Passed
Failure
Passed
Passed
register-sessiontestRemembersSession
Passed
Passed
Passed
Failure
Passed
Passed
register-sessiontestJoinSessionIsOptional
Passed
Passed
Passed
Failure
Passed
Passed
register-sessiontestRemembersSession
Passed
Passed
Passed
Failure
Passed
Passed
status-codestest404inResponse
Passed
Passed
Passed
Passed
Passed
Passed
status-codestest404inResponse
Passed
Passed
Passed
Passed
Passed
Passed
wrappingtestResponseWrapping
Passed
Passed
Passed
Passed
Passed
Passed
wrappingtestDeclaredFilterResponseWrapping
Passed
Passed
Failure
Passed
Passed
Passed
wrappingtestProgrammaticFilterResponseWrapping
Passed
Passed
Failure
Passed
Passed
Passed
wrappingtestDeclaredFilterRequestWrapping
Passed
Passed
Failure
Passed
Passed
Passed
wrappingtestProgrammaticFilterRequestWrapping
Passed
Passed
Failure
Passed
Passed
Passed
wrappingtestRequestWrapping
Passed
Passed
Passed
Passed
Passed
Passed

As can be see we now have 3 perfectly scoring servers; Payara, WildFly and Tomcat now pass every test being thrown at them. All 3 do this for the first time, and the slightly older versions of each of them contain a variety of (small) bugs that prevents a perfect score.

Liberty still fails the CDI tests as before, but there's a hack available that can let Liberty pass these. Since we test as much as possible out of the box here this hack was not applied. JACC propagation also doesn't work, but this is because there's no JACC provider available by default.

Perhaps the most surprising result of this round is that WebLogic is not longer completely broken when it comes to JASPIC. While WebLogic 12.1.x had decent support for JASPIC, a major regression was introduced in 12.2.1.0 were the basic cases didn't work properly anymore. When the basic cases fail it's almost pointless to continue testing since in practice when an authentication itself doesn't work anymore it doesn't matter so much whether say request wrapping is supported or not. WebLogic does have major problems with the "register session" feature (which likely caused the regression with basic authentication in the first place), doesn't support setting a custom principal (a major feature of JASPIC), and has problems with propagating to EJB. WebLogic fails the same CDI and JACC tests as Liberty does. Contrary to Liberty, WebLogic -does- have a default JACC provider but it's not activated out of the box.

TomEE performs very well, but has a small hick up when an injected request is used in a forwarded resource. It also fails the JACC propagation, but this is because TomEE doesn't implement JACC at all for the Web module (only for EJB).

An important additional aspect not shown in the test table above is whether JASPIC works out of the box (like e.g. a Servlet Filter does), or whether it needs (server specific) activation of some sort.

In this regard, Liberty, WebLogic, TomEE and Tomcat need zero activation. There's a small caveat with Liberty and that's if you use the server specific group to role mapping in combination with a JASPIC SAM, all role checking fails. This is a somewhat peculiar incompatibility. All other servers don't care whether the groups that are set come from a portable JASPIC SAM or from something proprietary when doing the server specific/proprietary group to role mapping.

Payara and WildFly both need an activation of some kind. Payara needs a glassfish-web.xml where default group to role mapping is activated (or alternatively, where groups are actually mapped to roles), while WildFly needs a jboss-web.xml where the "jaspitest" security domain is set. WildFly should eventually lift this mandated activation when the new Elytron security system is introduced, which could possibly happen in WildFly 11. Payara could eventually default to default group to role mapping. WebLogic made this move before, but this is somewhat of a major change that should be done carefully if indeed planned.

Conclusion

Three servers, namely WildFly 10.1, Payara 164 and Tomcat 8.5.6 now pass all tests, but two of them (WildFly and Payara) need some kind of activation so are not perfect-perfect, but still very, very close to it. TomEE performs very well too, with only a minor regression and all the major core authentication functionality working perfectly.

Liberty and WebLogic have a bit more work left to be done, where as core features are concerned Liberty fails the request/response wrapping partially, while WebLogic fails the custom principal, register session and EJB propagation.

In a next article we'll be looking at what things look like after we applied the CDI/Weld hack for Liberty and Weblogic, and if JACC propagation works on them when we install/activate a JACC provider.

Arjan Tijms

JSF 2.3 released!

$
0
0
After a long and at times intense spec and development process the JSF 2.3 EG is proud to announce that today we've released JSF 2.3.

JSF (JavaServer Faces), is a component based MVC framework that's part of Java EE. JSF 2.3 in particular is part of Java EE 8.

Major new features in JSF 2.3 are a tighter integration with CDI, support for WebSockets, a really cool component search expression framework (donated by PrimeFaces), basic support for extensionless URLs, and class level bean validation.

The age old native managed beans of JSF 2.3 have finally been deprecated (although they are still available for now) in favour of CDI. It's expected that these will be fully removed (pruned) in a future release.

The JSF 2.3 EG would like to thank everyone who contributed to JSF in whatever way, by creating bug reports, testing builds, providing comments and insights on the mailinglist and contributing code. Without those community contributions JSF 2.3 would not have been possible! Thanks to all our fantastic community members!

JSF 2.3 (Mojarra 2.3) can be downloaded per direct from the project's download page.

Maven coordinates for the implementation (includes API) are:


<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>2.3.0</version>
</dependency>

The full implementation can be used for Servlet containers such as Tomcat and Jetty.

Maven coordinates for just the API are:


<dependency>
<groupId>javax.faces</groupId>
<artifactId>javax.faces-api</artifactId>
<version>2.3</version>
</dependency>

The API jar can only be used as a compile time dependency.

Application servers Payara and GlassFish can be trivially updated by replacing the JSF 2.2 glassfish/modules/javax.faces.jar with the 2.3 version. It's usually a good idea to clear the OSGI cache after that (e.g. rm -rf [payara/gf gome]/ glassfish/domains/domain1/osgi-cache/felix/)

Arjan Tijms

Draft list of changes in Servlet 4.0

$
0
0
The proposed final draft (PDF) of the Servlet 4.0 spec has just been made available at GitHub.

The major new feature is HTTP/2 support and specifically the push support that comes with it. Java EE already has support for push via WebSockets (including WebSocket support in JSF 2.3), but there are other interesting changes as well, such as for instance the Mapping Discovery API.

The following contains a terse list of changes, taken from section A.1 of the above linked Servlet 4.0 PFD document. All mentioned references to sections are to that document.

  1. Requirement to support HTTP/2, see Section 1.2, “What is a Servlet Container?” on page 1-1 and “What is a Servlet?” on page 1 1. This includes HTTP/2 server push, see “HTTP/2 Server Push” on page 3 29.
  2. Modify javadoc for ServletContext getAttribute() and getInitParameter(), specify that NullPointerException must be thrown if the argument “name” is null.
  3. Modify javadoc for ServletContext.setAttribute() and setInitParameter() to specify that NullPointerException must be thrown if the “name” argument is null.
  4. DeprecateHttpServletRequestWrapper.isRequestedSessionIdFromUrl().
  5. Add @Deprecated to classes and methods with @deprecated in javadoc: ServletContext, ServletRequestWrapper, SingleThreadModel, UnavailableException, HttpServletRequest, HttpServletResponse, HttpServletResponseWrapper, HttpSession, HttpSessionContext, HttpUtils.
  6. Add default-context-path in the schema of web.xml and the description in Section 30., “default-context-path Element” on page 14-180 and the figure, Section FIGURE 14-1, “web-app Element Structure”.
  7. Modify Section 7.7.1, “Threading Issues” to clarify non-thread safety of objects vended from requests and responses.
  8. Clarify metadata-complete in Section 8.1, “Annotations and pluggability”.
  9. Add default to methods in ServletContextAttributeListener, ServletContextListener, ServletRequestAttributeListener, ServletRequestListener, HttpSessionActivationListener, HttpSessionAttributeListener, HttpSessionBindingListener, HttpSessionListener.
  10. Add javax.servlet.GenericFilter and javax.servlet.http.HttpFilter
  11. Clarify the merging of in web.xml and web-fragment.xml in Section 8.2.3, “Assembling the descriptor from web.xml, web-fragment.xml and annotations”.
  12. Modify javadoc for ServletContext.getEffectiveSessionTrackingModes() without specifying the default value.
  13. Remove DTDs and Schemas from binary artifact for Servlet API.
  14. Add getSessionTimeout and setSessionTimeout in ServletContext. See javadoc, Section 4.4.4 and Section 7.5.
  15. Add addJspFile() in ServletContext. See javadoc, Section 4.4.1.4 and Section 4.4.1.7.
  16. Add request-character-encoding and response-character-encoding in the schema of web.xml. See the corresponding descriptions of the elements in Section 31. and Section 32.
  17. Add getRequestCharacterEncoding, setRequestCharacterEncoding, getResponseCharacterEncoding and setResponseCharacterEncoding in ServletContext. Update the corresponding javadoc of ServletContext, ServletRequest and ServletResponse. See Section 4.4.5, Section 3.12 and Section 5.6.
  18. Describe mapping discovery API. See Section 12.3, “Runtime Discovery of Mappings”.
  19. Update the javadoc of Registration, ServletContext, ServletRegistration for the behaviors of returned sets.
  20. Clarify the behaviors of complete and dispatch in AsyncContext before the container-initiated dispatch that called startAsync has returned to the container. See Section , “AsyncContext” on page 2-13.
  21. Clarify interpretation of fileName parameter for method Part.write(). See the javadoc for details.
  22. Clarify encoding used for reading the request URL. See Section 12.1, “Use of URL Paths” on page 12-125 for details.
  23. Specified support for HTTP trailer. See Section 5.3, “HTTP Trailer” for details. Add getTrailerFields(), isTrailerFieldsReady() in HttpServletRequest and setTrailerFields in HttpServletResponse. See the corresponding javadoc.

Should the community take over JSF.next or not?

$
0
0
JSF aka JavaServer Faces is a component based MVC framework that's part of Java EE and is one of the oldest Java MVC frameworks that's still supported and actively used (version 1.0 was released in 2004).

Over time, Java EE itself has grown considerably and as such the resources required to maintain and evolve Java EE have grown as well. Now Oracle has indicated at several occasions that it just doesn't have the resources required for this, and for most constituent specs of Java EE it can do at most small updates, but in other cases can't do any updates at all.

In order to lessen this immense burden on Oracle somewhat, the community has largely taken over for JSF 2.3 and Java EE Security API 1.0. The following graph (taken from a presentation by JSF spec lead Ed Burns) gives an indication:

The question is how to continue for JSF.next?

Since the community has largely taken over JSF already, should this perhaps be made more formal by actually letting the community (individual, foundation, or even representative small company) take the lead in developing the next version of JSF? In such scenario, the existing JSF versions (2.3 and before) and their respective TCKs would stay with Oracle, but JSF.next (i.e. JSF 2.4 or 3.0) would be fully specified, implemented and released by the community (OmniFaces in particular, with possibly the help of others).

Is a large and important spec such as JSF better off at a large and responsible, albeit resource constrained, organisation such as Oracle, or do you want OmniFaces to take over the spec lead role? If you want, you can cast a vote in the poll below or leave a comment:

Do you want OmniFaces to take over the JSF spec lead role?

Viewing all 66 articles
Browse latest View live