Wednesday, May 4, 2016

Java EE's mysterious message policy

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"/>
    <response-policy/>
    <property name="loginPage" value="/login.jsf"/>
    <property name="loginErrorPage" value="/loginError.jsf"/>
  </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

Saturday, April 2, 2016

Servlet 4.0's mapping API previewed in Tomcat 9.0 m4

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

Monday, January 18, 2016

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

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
Module Test Payara 4.1.1.161-pre WildFly 10rc5 Liberty 9 beta 2016.1 Liberty 9 beta 2015.11
async-authentication testBasicAsync
Passed
Passed
Passed
Passed
basic-authentication testProtectedPageNotLoggedin
Passed
Passed
Passed
Passed
basic-authentication testProtectedPageLoggedin
Passed
Passed
Passed
Passed
basic-authentication testPublicPageLoggedin
Passed
Passed
Passed
Passed
basic-authentication testPublicPageNotLoggedin
Passed
Passed
Passed
Passed
basic-authentication testPublicAccessIsStateless
Passed
Passed
Passed
Passed
basic-authentication testProtectedAccessIsStateless
Passed
Passed
Passed
Passed
basic-authentication testProtectedAccessIsStateless2
Passed
Passed
Passed
Passed
basic-authentication testProtectedThenPublicAccessIsStateless
Passed
Passed
Passed
Passed
custom-principal testProtectedPageLoggedin
Passed
Passed
Passed
Passed
custom-principal testPublicPageLoggedin
Passed
Passed
Passed
Passed
custom-principal testPublicAccessIsStateless
Passed
Passed
Passed
Passed
custom-principal testProtectedAccessIsStateless
Passed
Passed
Passed
Passed
custom-principal testProtectedAccessIsStateless2
Passed
Passed
Passed
Passed
custom-principal testProtectedThenPublicAccessIsStateless
Passed
Passed
Passed
Passed
dispatching testBasicForwardViaProtectedResource
Passed
Passed
Passed
Passed
dispatching testBasicForwardViaPublicResource
Passed
Passed
Passed
Passed
dispatching testBasicIncludeViaPublicResource
Passed
Passed
Passed
Failure
dispatching-jsf-cdi testCDIForwardViaProtectedResource
Passed
Passed
Passed
Passed
dispatching-jsf-cdi testCDIForwardViaPublicResource
Passed
Passed
Passed
Passed
dispatching-jsf-cdi testCDIIncludeViaPublicResource
Passed
Passed
Passed
Failure
dispatching-jsf-cdi testJSFwithCDIForwardViaPublicResource
Passed
Passed
Passed
Passed
dispatching-jsf-cdi testJSFwithCDIForwardViaProtectedResource
Passed
Passed
Passed
Passed
dispatching-jsf-cdi testJSFwithCDIIncludeViaPublicResource
Failure
Failure
Failure
Failure
dispatching-jsf-cdi testJSFForwardViaPublicResource
Passed
Passed
Passed
Passed
dispatching-jsf-cdi testJSFForwardViaProtectedResource
Passed
Passed
Passed
Passed
dispatching-jsf-cdi testJSFIncludeViaPublicResource
Failure
Failure
Failure
Failure
ejb-propagation publicServletCallingProtectedEJB
Passed
Passed
Passed
Passed
ejb-propagation protectedServletCallingProtectedEJB
Passed
Passed
Passed
Passed
ejb-propagation publicServletCallingPublicEJBThenLogout
Passed
Passed
Passed
Passed
ejb-propagation protectedServletCallingPublicEJB
Passed
Passed
Passed
Passed
invoke-ejb-cdi protectedInvokeCDIFromSecureResponse
Passed
Passed
Failure
Failure
invoke-ejb-cdi protectedInvokeCDIFromCleanSubject
Passed
Passed
Passed
Passed
invoke-ejb-cdi protectedInvokeCDIFromValidateRequest
Passed
Passed
Failure
Failure
invoke-ejb-cdi publicInvokeCDIFromSecureResponse
Passed
Passed
Failure
Failure
invoke-ejb-cdi publicInvokeCDIFromValidateRequest
Passed
Passed
Failure
Failure
invoke-ejb-cdi publicInvokeCDIFromCleanSubject
Passed
Passed
Passed
Failure
invoke-ejb-cdi protectedInvokeEJBFromSecureResponse
Passed
Passed
Passed
Passed
invoke-ejb-cdi protectedInvokeEJBFromCleanSubject
Passed
Passed
Passed
Passed
invoke-ejb-cdi protectedInvokeEJBFromValidateRequest
Passed
Passed
Passed
Passed
invoke-ejb-cdi publicInvokeEJBFromSecureResponse
Passed
Passed
Passed
Passed
invoke-ejb-cdi publicInvokeEJBFromValidateRequest
Passed
Passed
Passed
Passed
invoke-ejb-cdi publicInvokeEJBFromCleanSubject
Passed
Passed
Passed
Passed
jacc-propagation callingJACCWhenAuthenticated
Passed
Failure
Failure
Failure
jacc-propagation callingJACCWhenAuthenticated
Passed
Failure
Failure
Failure
jacc-propagation callingJACCWhenNotAuthenticated
Passed
Passed
Failure
Failure
lifecycle testBasicSAMMethodsCalled
Passed
Passed
Passed
Passed
lifecycle testLogout
Passed
Passed
Passed
Passed
register-session testJoinSessionIsOptional
Passed
Passed
Passed
Passed
register-session testRemembersSession
Passed
Passed
Passed
Passed
status-codes test404inResponse
Passed
Passed
Passed
Passed
status-codes test404inResponse
Passed
Passed
Passed
Passed
wrapping testResponseWrapping
Passed
Passed
Passed
Passed
wrapping testRequestWrapping
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

Wednesday, January 6, 2016

Latest versions Payara and WildFly improve Java EE 7 authentication compliance

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
Module Test Payara 4.1.1.161-pre GlassFish 4.1.1 WildFly 10rc5 WildFly 10rc4 WildFly 9.0.1 WildFly 8.0.0
async-authentication testBasicAsync
Passed
Passed
Passed
Passed
Passed
Failed
basic-authentication testProtectedPageNotLoggedin
Passed
Passed
Passed
Passed
Passed
Passed
basic-authentication testProtectedPageLoggedin
Passed
Passed
Passed
Passed
Passed
Passed
basic-authentication testPublicPageLoggedin
Passed
Passed
Passed
Passed
Passed
Passed
basic-authentication testPublicPageNotLoggedin
Passed
Passed
Passed
Passed
Passed
Passed
basic-authentication testPublicAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
basic-authentication testProtectedAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
basic-authentication testProtectedAccessIsStateless2
Passed
Passed
Passed
Passed
Passed
Passed
basic-authentication testProtectedThenPublicAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
custom-principal testProtectedPageLoggedin
Passed
Failure
Passed
Passed
Passed
Passed
custom-principal testPublicPageLoggedin
Passed
Failure
Passed
Passed
Passed
Passed
custom-principal testPublicAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
custom-principal testProtectedAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
custom-principal testProtectedAccessIsStateless2
Passed
Passed
Passed
Passed
Passed
Passed
custom-principal testProtectedThenPublicAccessIsStateless
Passed
Passed
Passed
Passed
Passed
Passed
dispatching testBasicForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching testBasicForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching testBasicIncludeViaPublicResource
Passed
Passed
Passed
Passed
Passed
Failure
dispatching-jsf-cdi testCDIForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cdi testCDIForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cdi testCDIIncludeViaPublicResource
Passed
Passed
Passed
Passed
Passed
Failure
dispatching-jsf-cdi testJSFwithCDIForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cdi testJSFwithCDIForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cdi testJSFwithCDIIncludeViaPublicResource
Failure
Failure
Failure
Failure
Failure
Failure
dispatching-jsf-cdi testJSFForwardViaPublicResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cdi testJSFForwardViaProtectedResource
Passed
Passed
Passed
Passed
Passed
Passed
dispatching-jsf-cdi testJSFIncludeViaPublicResource
Failure
Failure
Failure
Failure
Failure
Failure
ejb-propagation publicServletCallingProtectedEJB
Passed
Passed
Passed
Passed
Passed
Failure
ejb-propagation protectedServletCallingProtectedEJB
Passed
Passed
Passed
Passed
Passed
Failure
ejb-propagation publicServletCallingPublicEJBThenLogout
Passed
Passed
Passed
Passed
Passed
Failure
ejb-propagation protectedServletCallingPublicEJB
Passed
Passed
Passed
Passed
Passed
Passed
invoke-ejb-cdi protectedInvokeCDIFromSecureResponse
Passed
Passed
Passed
Passed
Failure
Failure
invoke-ejb-cdi protectedInvokeCDIFromCleanSubject
Passed
Passed
Passed
Passed
Passed
Passed
invoke-ejb-cdi protectedInvokeCDIFromValidateRequest
Passed
Passed
Passed
Passed
Passed
Passed
invoke-ejb-cdi publicInvokeCDIFromSecureResponse
Passed
Passed
Passed
Passed
Failure
Failure
invoke-ejb-cdi publicInvokeCDIFromValidateRequest
Passed
Passed
Passed
Passed
Passed
Passed
invoke-ejb-cdi publicInvokeCDIFromCleanSubject
Passed
Passed
Passed
Passed
Passed
Passed
invoke-ejb-cdi protectedInvokeEJBFromSecureResponse
Passed
Failure
Passed
Passed
Failure
Passed
invoke-ejb-cdi protectedInvokeEJBFromCleanSubject
Passed
Passed
Passed
Passed
Passed
Passed
invoke-ejb-cdi protectedInvokeEJBFromValidateRequest
Passed
Failure
Passed
Passed
Passed
Passed
invoke-ejb-cdi publicInvokeEJBFromSecureResponse
Passed
Failure
Passed
Passed
Failure
Passed
invoke-ejb-cdi publicInvokeEJBFromValidateRequest
Passed
Failure
Passed
Passed
Passed
Passed
invoke-ejb-cdi publicInvokeEJBFromCleanSubject
Passed
Passed
Passed
Passed
Passed
Passed
jacc-propagation callingJACCWhenAuthenticated
Passed
Passed
Failure
Failure
Failure
Failure
jacc-propagation callingJACCWhenAuthenticated
Passed
Passed
Failure
Failure
Failure
Failure
jacc-propagation callingJACCWhenNotAuthenticated
Passed
Passed
Passed
Passed
Passed
Passed
lifecycle testBasicSAMMethodsCalled
Passed
Passed
Passed
Passed
Failure
Passed
lifecycle testLogout
Passed
Passed
Passed
Passed
Passed
Passed
register-session testJoinSessionIsOptional
Passed
Passed
Passed
Passed
Passed
Passed
register-session testRemembersSession
Passed
Passed
Passed
Passed
Passed
Passed
status-codes test404inResponse
Passed
Passed
Passed
Failure
Failure
Passed
status-codes test404inResponse
Passed
Passed
Passed
Failure
Failure
Passed
wrapping testResponseWrapping
Passed
Passed
Passed
Passed
Passed
Passed
wrapping testRequestWrapping
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