tag:blogger.com,1999:blog-44988893534287103132017-10-12T18:29:27.345-07:00Arjan Tijms' WeblogMusings of a Java EE developerArjan Tijmsnoreply@blogger.comBlogger72125tag:blogger.com,1999:blog-4498889353428710313.post-17029312200735702572017-08-23T08:02:00.000-07:002017-08-23T12:19:09.612-07:00Dynamically adding an interceptor to a build-in CDI beanIn Java EE's CDI, beans can be augmented via 2 artefacts; <a href="https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#decorators">Decorators</a> and <a href="https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#interceptors">Interceptors</a>. <p><b>Decorators</b> are typically owned by the application code and can decorate a bean that's shipped by the container (<a href="https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#additional_builtin_beans">build-in beans</a>) or a library. <p><b>Interceptors</b> are typically shipped by a library and can be applied (bound) to a bean that's owned by the application. <p>So how do you bind a library shipped interceptor to a library shipped/build-in bean? In CDI 1.2 and before this wasn't really possible, but in CDI 2.0 we can take advantage of the new <a href="https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#interception_factory">InterceptionFactory</a> to do just this. It's not entirely trivial yet, but it's doable. In this article we'll demonstrate how to apply the <a href="https://javaee.github.io/security-api/apidocs/javax/security/enterprise/authentication/mechanism/http/RememberMe.html">@RememberMe</a> interceptor binding from the new Java EE 8 Security spec to a build-in bean of type <a href="https://javaee.github.io/security-api/apidocs/javax/security/enterprise/authentication/mechanism/http/HttpAuthenticationMechanism.html">HttpAuthenticationMechanism</a>, which is from the Security spec as well. <p>First we configure our authentication mechanism by means of the following annotation: <pre class="brush: java;"><br />@BasicAuthenticationMechanismDefinition(<br /> realmName="foo"<br />)<br /></pre><p><small>&nbsp;</small> <p>This will cause the container to enable a build-in bean with interface type <i>HttpAuthenticationMechanism</i>, but having an unknown (vendor specific) implementation. <p>Next we'll definite an <a href="https://docs.jboss.org/cdi/spec/2.0/cdi-spec.html#alternatives">alternative</a> for this bean via a CDI producer: <pre class="brush: java;"><br />@Alternative<br />@Priority(500)<br />@ApplicationScoped<br />public class ApplicationInit {<br /> <br /> @Produces<br /> public HttpAuthenticationMechanism produce(InterceptionFactory&lt;HttpAuthenticationMechanismWrapper> interceptionFactory, BeanManager beanManager) {<br /> return ...<br /> }<br /></pre> <small><i>Note that perhaps somewhat counter intuitively the <a href="http://docs.oracle.com/javaee/7/api/javax/enterprise/inject/Alternative.html">@Alternative</a> annotation is put on the bean hosting the producer method, not on the producer method itself.</i></small> <p>A small challenge here is to obtain the bean with type <i>HttpAuthenticationMechanism</i> that would have been chosen by the CDI runtime had our producer not been there. For a decorator this is easy as CDI makes that exact bean injectable via the <a href="https://docs.jboss.org/cdi/api/2.0/javax/enterprise/inject/Decorated.html">@Decorated</a> qualifier. Here we'll have to do this manually. One way is to get all the beans of type <i>HttpAuthenticationMechanism</i> from the bean manager (this will include both alternatives and non-alternatives), filter ourselves from that set and then let the bean manager resolve the set to the one that would be chosen for injection. We then create a reference for that chosen bean. <p>The following shows this in code: <pre class="brush: java;"><br />HttpAuthenticationMechanism mechanism =<br /> createRef(<br /> beanManager.resolve(<br /> beanManager.getBeans(HttpAuthenticationMechanism.class)<br /> .stream()<br /> .filter(e -> !e.getBeanClass().equals(ApplicationInit.class))<br /> .collect(toSet())), <br /> beanManager);<br /></pre><p><small>&nbsp;</small> <p>With <i>createRef</I> being defined as: <pre class="brush: java;"><br />HttpAuthenticationMechanism createRef(Bean&lt;?> bean, BeanManager beanManager) {<br /> return (HttpAuthenticationMechanism) <br /> beanManager.getReference(<br /> bean, <br /> HttpAuthenticationMechanism.class, <br /> beanManager.createCreationalContext(bean));<br />}<br /></pre><p><small>&nbsp;</small> <p>We now have an instance to the bean to which we like to apply the interceptor binding. Unfortunately, there's a somewhat peculiar and very nasty note in the CDI spec regarding the method that creates a proxy with the required interceptor attached: <blockquote><i>If the provided instance is an internal container construct (such as client proxy), non-portable behavior results.</i></blockquote> <p>Since the <i>HttpAuthenticationMechanism</i> is a client proxy (it's application scoped by spec definition) we have no choice but to introduce some extra ceremony here and that's by providing a wrapper ourselves. The interceptor will be applied to the wrapper then, and the wrapper will delegate to the actual <i>HttpAuthenticationMechanism</i> instance: <p>&nbsp; <pre class="brush: java;"><br />HttpAuthenticationMechanismWrapper wrapper = <br /> new HttpAuthenticationMechanismWrapper(mechanism);<br /></pre><p><small>&nbsp;</small> <p>Having our <i>HttpAuthenticationMechanism</i> instance ready, we can now dynamically configure an annotation instance. Such instance can be created via CDI's provided <a href="https://docs.jboss.org/cdi/api/2.0/javax/enterprise/util/AnnotationLiteral.html">AnnotationLiteral</a> helper type: <pre class="brush: java;"><br />interceptionFactory.configure().add(<br /> new RememberMeAnnotationLiteral(<br /> 86400, "", // cookieMaxAgeSeconds<br /> false, "", // cookieSecureOnly<br /> true, "", // cookieHttpOnly<br /> "JREMEMBERMEID", // cookieName<br /> true, "" // isRememberMe<br /> )<br />);<br /></pre><p><small>&nbsp;</small> <p>Finally, we create the above mentioned new proxy with the configured interceptor binding applied to it using the interception factory's createInterceptedInstance method and return this from our producer method: <pre class="brush: java;"><br />return interceptionFactory.createInterceptedInstance(<br /> new HttpAuthenticationMechanismWrapper(wrapper));<br /></pre><p><small>&nbsp;</small> <p>A full example can be found in the <a href="https://github.com/javaee-samples/javaee8-samples/blob/master/security/dynamic-rememberme/src/main/java/org/javaee8/security/dynamic/rememberme/ApplicationInit.java">Java EE 8 samples project</a>. <p>Note that there's a small caveat here; if the Interceptor needs access to the interceptor bindings (which is almost always the case when the binding has attributes), you can't just inspect the target type as one would usually do in CDI 1.2 and earlier code. The interceptor binding annotation is not physically present on the type. At the moment it's <a href="http://lists.jboss.org/pipermail/cdi-dev/2017-August/009978.html">not entirely clear</a> how to obtain these in a portable way. The interceptors in the Java EE Security RI (Soteria) uses an <a href="https://github.com/javaee/security-soteria/blob/master/impl/src/main/java/org/glassfish/soteria/cdi/RememberMeInterceptor.java#L198">RI specific way</a> for now. <p>The example was <a href="https://travis-ci.org/javaee-samples/javaee8-samples/builds/267394312">tested</a> on <a href="https://www.payara.fish">Payara Server</a> 5, of which a snapshot can be downloaded from the <a href="https://oss.sonatype.org/content/repositories/snapshots/fish/payara/distributions/payara/5.0.0.173-SNAPSHOT/">snapshot repository</a>. An initial alpha will be released very soon, but in the mean time the latest version can be downloaded here: <br/> <a href="https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=fish.payara.distributions&a=payara&v=5.0.0.173-SNAPSHOT&p=zip">payara-5.0.0.173-SNAPSHOT.zip</a>. <p><i>Arjan Tijms</i> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com0tag:blogger.com,1999:blog-4498889353428710313.post-32063413570104150632017-08-17T05:34:00.001-07:002017-08-17T05:34:09.081-07:00Extensionless URLs with JSF 2.3An extensionless URL is a URL without a final suffix like <i>.xhtml</i>, <i>.html</i>, <i>.jsp</i>, etc. Such a suffix is seen as technical "clutter" that's hard to remember for humans. Servers often need it though to route a request to the right controller. <p>JSF, a Java EE MVC framework, has supported extensionless URLs for some time via PrettyFaces (now merged to the general <a href="https://github.com/ocpsoft/rewrite">Rewrite</a> framework) and <a href="http://arjan-tijms.omnifaces.org/2013/03/easy-extensionless-urls-in-jsf-with.html">OmniFaces</a>. Both of these solutions used various workarounds to trick JSF into working with extensionless URLs. <p>Though JSF 2.3 does, unfortunately, still not support extensionless URLs fully out of the box via e.g. a single parameter, it can provide support for it by basically combining the new support for <a href="http://arjan-tijms.omnifaces.org/p/jsf-23.html#1260">exact mapping</a> and the API for <a href="http://arjan-tijms.omnifaces.org/p/jsf-23.html#1435">obtaining a list of all view resources</a>. Additionally combining this with the Servlet 3.1 feature for dynamically adding Servlet mappings and some JDK8 streaming and lambdas, makes it possible to enable extensionless support with just 2 statements (albeit somewhat long statements): <p><pre class="brush: java;"><br />@WebListener<br />public class MappingInit implements ServletContextListener {<br /> <br /> @Override<br /> public void contextInitialized(ServletContextEvent sce) {<br /> FacesContext context = FacesContext.getCurrentInstance();<br /> <br /> sce.getServletContext()<br /> .getServletRegistrations()<br /> .values()<br /> .stream()<br /> .filter(e -> e.getClassName().equals(FacesServlet.class.getName()))<br /> .findAny()<br /> .ifPresent(<br /> reg -> context.getApplication()<br /> .getViewHandler()<br /> .getViews(context, "/", RETURN_AS_MINIMAL_IMPLICIT_OUTCOME)<br /> .forEach(e -> reg.addMapping(e)));<br /> }<br />}<br /></pre> <p>What the above code does is finding the existing <i>FacesServlet</i>, then getting all views for the entire application in a form that happens to be exactly suitable for extensionless URLs, and then adding each of them as mapping to the <i>FacesServlet</i> we previously found. <p>After adding the above shown <i>WebListener</I> to an application, its view can be requested via URLs like <i>example.com/login</i>, <i>example.com/users/all</i> etc. <p>The example was <a href="https://travis-ci.org/javaee-samples/javaee8-samples/builds/265365535">tested</a> on <a href="https://www.payara.fish">Payara Server</a> 5, of which a snapshot can be downloaded from the <a href="https://oss.sonatype.org/content/repositories/snapshots/fish/payara/distributions/payara/5.0.0.173-SNAPSHOT/">snapshot repository</a>. An initial alpha will be released very soon, but in the mean time the latest version can be downloaded here: <br/> <a href="https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=fish.payara.distributions&a=payara&v=5.0.0.173-SNAPSHOT&p=zip">payara-5.0.0.173-SNAPSHOT.zip</a>. <p><i>Arjan Tijms</i>Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com1tag:blogger.com,1999:blog-4498889353428710313.post-18706239005814011152017-08-15T04:08:00.000-07:002017-08-15T04:11:50.529-07:00Dynamic beans in CDI 2.0A <a href="http://arjan-tijms.omnifaces.org/2012/08/dynamic-cdi-producers.html">while ago</a> we wrote about CDIs ability to dynamically add <a href="https://docs.jboss.org/cdi/api/2.0/javax/enterprise/inject/spi/Bean.html">Bean&lt;T&gt;</a> instances to the CDI runtime. <p>A Bean&lt;T&gt; is a kind of factory for beans, that makes types available for injection, lookup via the <a href="http://docs.oracle.com/javaee/7/api/javax/enterprise/inject/spi/BeanManager.html">bean manager</a>, or by referencing them in expression language. CDI producers (via the <i><a href="https://docs.jboss.org/cdi/api/2.0/javax/enterprise/inject/Produces.html">@Produces</a></i> annotation) fulfil a somewhat similar role, but they essentially only make the "create instance" method dynamic; the rest (like scope, types, etc) is more or less static. A programmatically added Bean&lt;T&gt; essentially makes all those aspects dynamic. <p>As the <a href="http://arjan-tijms.omnifaces.org/2012/08/dynamic-cdi-producers.html">previous</a> article showed, dynamically adding such Bean&lt;T&gt; is a bit more work and it's quite verbose, as well as a little complex as the developer has to find out what to return as a default for various methods that are not directly of interest. <p>CDI 2.0 has addressed some of the above issues by providing a <a href="http://docs.jboss.org/cdi/api/2.0/javax/enterprise/inject/spi/configurator/BeanConfigurator.html">very convenient builder</a> that not only makes creating a Bean&lt;T&gt; instance far less verbose, but also takes away most of the guesswork. The following shows an example: <pre class="brush: java;"><br />public class CdiExtension implements Extension {<br /><br /> public void afterBean(final @Observes AfterBeanDiscovery afterBeanDiscovery) {<br /> afterBeanDiscovery<br /> .addBean()<br /> .scope(ApplicationScoped.class)<br /> .types(MyBean.class)<br /> .id("Created by " + CdiExtension.class)<br /> .createWith(e -> new MyBeanImpl("Hi!"));<br /> }<br />}<br /></pre> <p>The above makes a bean available for injection into <i>MyBean</I> injection points and with the <i><a href="http://docs.oracle.com/javaee/7/api/javax/enterprise/context/ApplicationScoped.html">@ApplicationScoped</a></i> scope, backed by a <i>MyBeanImpl</I> class. <p>A fully working example is provided in the <a href="https://github.com/javaee-samples/javaee8-samples/tree/master/cdi/dynamic-bean">Java EE 8 Samples project</a>. <p>The example was <a href="https://travis-ci.org/javaee-samples/javaee8-samples/builds/264523120">tested</a> on <a href="https://www.payara.fish">Payara Server</a> 5, of which a snapshot can be downloaded from the <a href="https://oss.sonatype.org/content/repositories/snapshots/fish/payara/distributions/payara/5.0.0.173-SNAPSHOT/">snapshot repository</a>. An initial alpha will be released very soon, but in the mean time the latest version can be downloaded here: <br/> <a href="https://oss.sonatype.org/service/local/artifact/maven/redirect?r=snapshots&g=fish.payara.distributions&a=payara&v=5.0.0.173-SNAPSHOT&p=zip">payara-5.0.0.173-SNAPSHOT.zip</a>. <p><i>Arjan Tijms</i> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com2tag:blogger.com,1999:blog-4498889353428710313.post-19322081724353131382017-06-13T06:42:00.001-07:002017-06-13T09:40:07.827-07:00Should the community take over JSF.next or not?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 <a href="https://zeroturnaround.com/rebellabs/java-web-frameworks-index-by-rebellabs">and actively used</a> (version 1.0 was <a href="https://en.wikipedia.org/wiki/JavaServer_Faces#Versions">released in 2004</a>). <p> Over time, Java EE itself has <a href="https://en.wikipedia.org/wiki/Java_EE_version_history">grown considerably</a> 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. <p> In order to lessen this immense burden on Oracle somewhat, <a href="https://static.rainfocus.com/oracle/oow16/.../CON7981_BURNS_MANN_JSF23.pdf">the community has largely taken over for JSF 2.3</a> and Java EE Security API 1.0. The following graph (taken from a presentation by JSF spec lead Ed Burns) gives an indication: <p> <div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-UhRdgCAdm7g/WT_jjHmgEfI/AAAAAAAAAxQ/7QYwe8eeA-8Zb3WXidCVLGvXVH5i8iFLACLcB/s1600/jsf23-community.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://4.bp.blogspot.com/-UhRdgCAdm7g/WT_jjHmgEfI/AAAAAAAAAxQ/7QYwe8eeA-8Zb3WXidCVLGvXVH5i8iFLACLcB/s320/jsf23-community.png" width="320" height="199" data-original-width="988" data-original-height="614" /></a></div> <p>The question is <a href="https://javaee.groups.io/g/jsf-spec/topic/filing_for_jsf_next/5045616">how to continue for JSF.next</a>? <p>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). <p>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: <h2 class='title'>Do you want OmniFaces to take over the JSF spec lead role?</h2><iframe allowtransparency='true' frameborder='0' height='180' name='poll-widget-2485419822756739149' src='http://www.google.com/reviews/polls/display/-2485419822756739149/blogger_template/run_app?txtclr=%23222222&lnkclr=%232288bb&chrtclr=%232288bb&font=normal+normal+12px+Arial,+Tahoma,+Helvetica,+FreeSans,+sans-serif&hideq=true&purl=http://arjan-tijms.omnifaces.org/' style='border:none; width:100%;'></iframe> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com9tag:blogger.com,1999:blog-4498889353428710313.post-85021764126992802682017-05-24T03:39:00.000-07:002017-05-24T03:39:08.359-07:00Draft list of changes in Servlet 4.0The proposed final draft (PDF) of the Servlet 4.0 spec has just been <a href="https://javaee.github.io/servlet-spec/downloads/servlet-4.0/servlet-4_0_PFD.pdf">made available at GitHub</a>. <p>The major new feature is <a href="https://en.wikipedia.org/wiki/HTTP/2">HTTP/2 support</a> and specifically the push support that comes with it. Java EE already has support for push via WebSockets (including <a href="http://arjan-tijms.omnifaces.org/p/jsf-23.html#1396">WebSocket support in JSF 2.3</a>), but there are other interesting changes as well, such as for instance the <a href="http://arjan-tijms.omnifaces.org/2016/04/servlet-40s-mapping-api-previewed-in.html">Mapping Discovery API</a>. <p>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. <ol> <li> 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. <li> Modify javadoc for ServletContext getAttribute() and getInitParameter(), specify that NullPointerException must be thrown if the argument “name” is null. <li> Modify javadoc for ServletContext.setAttribute() and setInitParameter() to specify that NullPointerException must be thrown if the “name” argument is null. <li> DeprecateHttpServletRequestWrapper.isRequestedSessionIdFromUrl(). <li> Add @Deprecated to classes and methods with @deprecated in javadoc: ServletContext, ServletRequestWrapper, SingleThreadModel, UnavailableException, HttpServletRequest, HttpServletResponse, HttpServletResponseWrapper, HttpSession, HttpSessionContext, HttpUtils. <li> 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”. <li> Modify Section 7.7.1, “Threading Issues” to clarify non-thread safety of objects vended from requests and responses. <li> Clarify metadata-complete in Section 8.1, “Annotations and pluggability”. <li> Add default to methods in ServletContextAttributeListener, ServletContextListener, ServletRequestAttributeListener, ServletRequestListener, HttpSessionActivationListener, HttpSessionAttributeListener, HttpSessionBindingListener, HttpSessionListener. <li> Add javax.servlet.GenericFilter and javax.servlet.http.HttpFilter <li> Clarify the merging of <distributable> in web.xml and web-fragment.xml in Section 8.2.3, “Assembling the descriptor from web.xml, web-fragment.xml and annotations”. <li> Modify javadoc for ServletContext.getEffectiveSessionTrackingModes() without specifying the default value. <li> Remove DTDs and Schemas from binary artifact for Servlet API. <li> Add getSessionTimeout and setSessionTimeout in ServletContext. See javadoc, Section 4.4.4 and Section 7.5. <li> Add addJspFile() in ServletContext. See javadoc, Section 4.4.1.4 and Section 4.4.1.7. <li> 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. <li> 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. <li> Describe mapping discovery API. See Section 12.3, “Runtime Discovery of Mappings”. <li> Update the javadoc of Registration, ServletContext, ServletRegistration for the behaviors of returned sets. <li> 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. <li> Clarify interpretation of fileName parameter for method Part.write(). See the javadoc for details. <li> Clarify encoding used for reading the request URL. See Section 12.1, “Use of URL Paths” on page 12-125 for details. <li> 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. </ol>Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com0tag:blogger.com,1999:blog-4498889353428710313.post-10896196421056015292017-03-28T15:18:00.000-07:002017-03-28T15:18:50.945-07:00JSF 2.3 released!After a long and at times intense spec and development process the <a href="https://www.jcp.org/en/jsr/detail?id=372">JSF 2.3 EG</a> is proud to announce that today we've released <a href="https://javaserverfaces.java.net/nonav/2.3/releasenotes.html">JSF 2.3</a>. <p>JSF (JavaServer Faces), is a component based <a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">MVC framework</a> that's part of Java EE. JSF 2.3 in particular is part of Java EE 8. <p><a href="https://javaserverfaces.java.net/nonav/2.3/whatsnew.html">Major new features</a> in JSF 2.3 are a tighter integration with CDI, support for WebSockets, a really cool component search expression framework (donated by <a href="https://primefaces.org">PrimeFaces</a>), basic support for extensionless URLs, and class level bean validation. <p>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. <p>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! <p>JSF 2.3 (Mojarra 2.3) can be downloaded per direct from the project's <a href="https://javaserverfaces.java.net/nonav/2.3/download.html">download page</a>. <p>Maven coordinates for the implementation (includes API) are: <pre class="brush: xml;"><br />&lt;dependency&gt;<br /> &lt;groupId&gt;org.glassfish&lt;/groupId&gt;<br /> &lt;artifactId&gt;javax.faces&lt;/artifactId&gt;<br /> &lt;version&gt;2.3.0&lt;/version&gt;<br />&lt;/dependency&gt;<br /></pre> <p>The full implementation can be used for Servlet containers such as Tomcat and Jetty. <p>Maven coordinates for just the API are: <pre class="brush: xml;"><br />&lt;dependency&gt;<br /> &lt;groupId&gt;javax.faces&lt;/groupId&gt;<br /> &lt;artifactId&gt;javax.faces-api&lt;/artifactId&gt;<br /> &lt;version&gt;2.3&lt;/version&gt;<br />&lt;/dependency&gt;<br /></pre> <p>The API jar can only be used as a <b>compile</b> time dependency. <p>Application servers <a href="http://payara.fish">Payara</a> and <a href="https://glassfish.java.net">GlassFish</a> can be trivially updated by replacing the JSF 2.2 <i>glassfish/modules/javax.faces.jar</i> with the 2.3 version. It's usually a good idea to clear the OSGI cache after that (e.g. <i>rm -rf [payara/gf gome]/ glassfish/domains/domain1/osgi-cache/felix/</i>) <p><i>Arjan Tijms</i>Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com18tag:blogger.com,1999:blog-4498889353428710313.post-44748186322468534802016-12-04T14:30:00.000-08:002016-12-04T14:30:12.186-08:00The state of portable authentication in Java EE, end 2016 updateIn the <a href="http://arjan-tijms.omnifaces.org/2016/01/latest-versions-payara-and-wildfly.html">beginning</a>and <a href="http://arjan-tijms.omnifaces.org/2016/06/the-state-of-portable-authentication-in.html">middle</a> 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. <p>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. <p>Tests were added for <a href="https://github.com/javaee-samples/javaee7-samples/commit/654dcb70f639b2b9987c6b00a41ae8c60e75637f">request.authenticate</a>, <a href="https://github.com/javaee-samples/javaee7-samples/commit/d25a239cf4054c02afb1fa171b359b0fda46106e">an injected CDI request</a>, <a href="https://github.com/javaee-samples/javaee7-samples/commit/b8569195070f355d04f8f869f162f13de0dafa53">the servlet path after a forward</a>, <a href="https://github.com/javaee-samples/javaee7-samples/commit/cca87f545c505d69a7ed1299adfbfb5cc583c604">isMandatory in a SAM</a>, and finally for <a href="https://github.com/javaee-samples/javaee7-samples/commit/fe85e711807c194e22d3414f55fb1a3d92d05626">a SAM request to be seen by a Filter</a>. 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. <p>The results of running the <a href="https://github.com/javaee-samples/javaee7-samples/tree/master/jaspic">latest series of JASPIC tests</a> are shown below: <p><div style="font-size:75%;"><table border="1"><caption>Running the Java EE 7 samples JASPIC tests</caption><tr style="background-color:LightGray"> <th>Module</th> <th>Test</th> <th>Payara 164</th> <th>WildFly 10.1</th> <th>Liberty 2016-11</th> <th>Weblogic 12.2.1.2</th> <th>TomEE 7.0.2</th> <th>Tomcat 8.5.6</th></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/async-authentication">async-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/async-authentication/src/test/java/org/javaee7/jaspic/asyncauthentication/AsyncAuthenticationPublicTest.java">testBasicAsync</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationProtectedTest.java">testProtectedPageNotLoggedin</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationProtectedTest.java">testProtectedPageLoggedin</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationPublicTest.java">testPublicPageLoggedin</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationPublicTest.java">testPublicPageNotLoggedin</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedAccessIsStateless</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedAccessIsStateless2</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedThenPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalProtectedTest.java">testProtectedPageLoggedin</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Authentication succeeded and username and roles are correct, but principal type is not the expected custom type.">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalPublicTest.java">testPublicPageLoggedin</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Username and roles are correct, but principal type is not the expected custom type.">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedAccessIsStateless</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedAccessIsStateless2</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedThenPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicForwardTest.java">testBasicForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicForwardTest.java">testBasicForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicIncludeTest.java">testBasicIncludeViaPublicResource</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIForwardTest.java">testCDIForwardWithRequestProtected</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIForwardTest.java">testCDIForwardWithRequestInjectPublic</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Servletpath reported by injected request after forward from SAM not as expected.">Failure</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIForwardTest.java">testCDIForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIForwardTest.java">testCDIForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIForwardTest.java">testCDIForwardWithRequestPublic</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIForwardTest.java">testCDIForwardWithRequestInjectProtected</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Servletpath reported by injected request after forward from SAM not as expected.">Failure</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIIncludeTest.java">testCDIIncludeViaPublicResource</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFCDIForwardTest.java">testJSFwithCDIForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFCDIForwardTest.java">testJSFwithCDIForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFForwardTest.java">testJSFForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFForwardTest.java">testJSFForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/ProtectedEJBPropagationTest.java">publicServletCallingProtectedEJB</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Web has user principal set, but EJB not.">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/ProtectedEJBPropagationTest.java">protectedServletCallingProtectedEJB</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Web has user principal set, but EJB not.">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/PublicEJBPropagationLogoutTest.java">publicServletCallingPublicEJBThenLogout</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/PublicEJBPropagationTest.java">protectedServletCallingPublicEJB</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-register-session">ejb-register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionCustomPrincipalEJBPropagationTest.java">testRemembersSession</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Authentication succeeded and username and roles are correct, but principal type is not the expected custom type.">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-register-session">ejb-register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionEJBPropagationTest.java">testRemembersSession</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Could not access protected page, but should be able to. Did the container not remember the authenticated identity via 'javax.servlet.http.registerSession'?">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromSecureResponse</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Response did not contain output from CDI bean for secureResponse for protected resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div tooltip="Response did not contain output from CDI bean for secureResponse for protected resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromCleanSubject</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromValidateRequest</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Response did not contain output from CDI bean for validateRequest for protected resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div tooltip="Response did not contain output from CDI bean for validateRequest for protected resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIUseInjectedRequestFromValidateRequest</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Response did not contain output from CDI bean using an inject request for validateRequest for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div tooltip="Response did not contain output from CDI bean using an inject request for validateRequest for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromSecureResponse</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Response did not contain output from CDI bean for secureResponse for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div tooltip="Response did not contain output from CDI bean for secureResponse for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromValidateRequest</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Response did not contain output from CDI bean for validateRequest for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div tooltip="Response did not contain output from CDI bean for validateRequest for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIUseInjectedRequestFromCleanSubject</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIUseInjectedRequestFromSecureResponse</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Response did not contain output from CDI bean using an inject request for secureResponse for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div tooltip="Response did not contain output from CDI bean using an inject request for secureResponse for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromCleanSubject</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromSecureResponse</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromCleanSubject</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromValidateRequest</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromSecureResponse</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromValidateRequest</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromCleanSubject</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation">jacc-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation/src/test/java/org/javaee7/jaspic/jaccpropagation/JACCPropagationProtectedTest.java">callingJACCWhenAuthenticated</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="JACC doesn't seem to be available.">Failure</div></td> <td bgcolor="LightCoral"><div tooltip="JACC doesn't seem to be available.">Failure</div></td> <td bgcolor="LightCoral"><div tooltip="JACC doesn't seem to be available.">Failure</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation">jacc-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation/src/test/java/org/javaee7/jaspic/jaccpropagation/JACCPropagationPublicTest.java">callingJACCWhenAuthenticated</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="JACC doesn't seem to be available.">Failure</div></td> <td bgcolor="LightCoral"><div tooltip="JACC doesn't seem to be available.">Failure</div></td> <td bgcolor="LightCoral"><div tooltip="JACC doesn't seem to be available.">Failure</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation">jacc-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation/src/test/java/org/javaee7/jaspic/jaccpropagation/JACCPropagationPublicTest.java">callingJACCWhenNotAuthenticated</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="JACC doesn't seem to be available.">Failure</div></td> <td bgcolor="LightCoral"><div tooltip="JACC doesn't seem to be available.">Failure</div></td> <td bgcolor="LightCoral"><div tooltip="JACC doesn't seem to be available.">Failure</div></td> <td>-</td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle">lifecycle</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle/src/test/java/org/javaee7/jaspic/lifecycle/AuthModuleMethodInvocationTest.java">testBasicSAMMethodsCalled</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle">lifecycle</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle/src/test/java/org/javaee7/jaspic/lifecycle/AuthModuleMethodInvocationTest.java">testLogout</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle">lifecycle</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle/src/test/java/org/javaee7/jaspic/lifecycle/IsMandatoryTest.java">testProtectedIsMandatory</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle">lifecycle</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle/src/test/java/org/javaee7/jaspic/lifecycle/IsMandatoryTest.java">testPublicIsNonMandatory</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/programmatic-authentication">programmatic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/programmatic-authentication/src/test/java/org/javaee7/jaspic/programmaticauthentication/ProgrammaticAuthenticationTest.java">testAuthenticateFailFirstTwice</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/programmatic-authentication">programmatic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/programmatic-authentication/src/test/java/org/javaee7/jaspic/programmaticauthentication/ProgrammaticAuthenticationTest.java">testAuthenticate</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/programmatic-authentication">programmatic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/programmatic-authentication/src/test/java/org/javaee7/jaspic/programmaticauthentication/ProgrammaticAuthenticationTest.java">testAuthenticateFailFirstOnce</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionCustomPrincipalTest.java">testJoinSessionIsOptional</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Authentication succeeded and username and roles are correct, but principal type is not the expected custom type.">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionCustomPrincipalTest.java">testRemembersSession</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Authentication succeeded and username and roles are correct, but principal type is not the expected custom type.">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionTest.java">testJoinSessionIsOptional</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Could not access protected page, but should be able to. Did the container not remember the authenticated identity via 'javax.servlet.http.registerSession'?">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionTest.java">testRemembersSession</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Could not access protected page, but should be able to. Did the container not remember the authenticated identity via 'javax.servlet.http.registerSession'?">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes">status-codes</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes/src/test/java/org/javaee7/jaspic/statuscodes/ProtectedStatusCodesTest.java">test404inResponse</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes">status-codes</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes/src/test/java/org/javaee7/jaspic/statuscodes/PublicStatusCodesTest.java">test404inResponse</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping">wrapping</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping/src/test/java/org/javaee7/jaspic/wrapping/WrappingTest.java">testResponseWrapping</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping">wrapping</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping/src/test/java/org/javaee7/jaspic/wrapping/WrappingTest.java">testDeclaredFilterResponseWrapping</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Response wrapped by SAM did not arrive in declared Filter.">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping">wrapping</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping/src/test/java/org/javaee7/jaspic/wrapping/WrappingTest.java">testProgrammaticFilterResponseWrapping</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Response wrapped by SAM did not arrive in programmatic Filter.">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping">wrapping</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping/src/test/java/org/javaee7/jaspic/wrapping/WrappingTest.java">testDeclaredFilterRequestWrapping</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Request wrapped by SAM did not arrive in declared Filter.">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping">wrapping</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping/src/test/java/org/javaee7/jaspic/wrapping/WrappingTest.java">testProgrammaticFilterRequestWrapping</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Request wrapped by SAM did not arrive in programmatic Filter.">Failure</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping">wrapping</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping/src/test/java/org/javaee7/jaspic/wrapping/WrappingTest.java">testRequestWrapping</a></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td> <td bgcolor="lightgreen"><div tooltip="">Passed</div></td></tr></table></div> <p>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. <p>Liberty still fails the CDI tests as before, but there's a <a href="https://github.com/javaee-security-spec/soteria/blob/master/impl/src/main/java/org/glassfish/soteria/cdi/spi/impl/LibertyCDIPerRequestInitializer.java#L60">hack</a> 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. <p>Perhaps the most surprising result of this round is that WebLogic is not longer <a href="http://arjan-tijms.omnifaces.org/2015/11/the-state-of-portable-authentication.html">completely broken</a> 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. <p>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). <p>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. <p>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. <p>Payara and WildFly both need an activation of some kind. Payara needs a <i>glassfish-web.xml</i> where default group to role mapping is activated (or alternatively, where groups are actually mapped to roles), while WildFly needs a <i>jboss-web.xml</i> where the "jaspitest" security domain is set. WildFly should eventually lift this mandated activation when the new <a href="https://developer.jboss.org/wiki/WildFlyElytron-ProjectSummary">Elytron</a> 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. <p><h3>Conclusion</h3> <p>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. <p>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. <p>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. <p><i>Arjan Tijms</i> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com0tag:blogger.com,1999:blog-4498889353428710313.post-32436204732881196472016-08-29T15:57:00.000-07:002016-08-29T15:57:55.632-07:00Custom authorization rules on IBM LibertyLast month we presented a way how a Java EE application can <a href="http://arjan-tijms.omnifaces.org/2016/07/simplified-custom-authorization-rules.html">provide custom rules for authorization</a>. The code shown in that article was developed and tested using <a href="http://payara.fish">Payara</a>. We're now going to look at how the code can be used on some other servers, starting with IBM's Liberty. <p> 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 <i>server.xml</i> 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). <p>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). <p>Summarised we have to: <ul><li> Create an OSGi bundle </li><li> Add our JACC provider jar to this bundle </li><li> Implement a Liberty specific service that returns the policy and factory instances from our provider </li><li> Make sure we have the right imports and exports </li><li> Create a Liberty Feature that references the previously created bundle and provides the right exports </li><li> Installing the feature in Liberty </li></ul> <p>IBM provides <a href="http://www.ibm.com/support/knowledgecenter/SSAW57_9.0.0/com.ibm.websphere.wlp.nd.doc/ae/twlp_developing_jacc_auth_provider.html">documentation</a> 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. <p>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: <blockquote><i>Package the component into an OSGi bundle that is part of your user feature, along with your JACC provider.</i></blockquote> 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: <p><h3>Create an OSGi bundle</h3> <p>Luckily IBM also has instructions for a <a href="https://developer.ibm.com/wasdev/docs/create_your_own_simple_hello_world_user_feature">"hello world" user feature</a>, 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 <i>org.osgi.framework</i> could not be found. Eventually it appeared that next to a <i>target runtime</i> (which was set to the installed Liberty server), Eclipse also has the notion of a <i>target platform</i>. 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 <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=159072">global for your entire workspace</a> and the latter is per project. <p>The target platform can be set in Eclipse in <i>Preferences -> Plug-in Development -> Target Platform</i>. See the screenshot below: <div><a href="https://3.bp.blogspot.com/-9LUTq6QDHd8/V8SYxjmqT_I/AAAAAAAAAcA/1cGC_SsJ8poOdbV98g5bLABeX7byTVreQCLcB/s1600/eclipse_target_platform.png" imageanchor="1" ><img border="0" src="https://3.bp.blogspot.com/-9LUTq6QDHd8/V8SYxjmqT_I/AAAAAAAAAcA/1cGC_SsJ8poOdbV98g5bLABeX7byTVreQCLcB/s400/eclipse_target_platform.png" width="400" height="277" /></a></div> <p>Switching to "Running platform" solved the compile error for <i>org.osgi.framework</i>, 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. <p><h3>Add our JACC provider jar to this bundle</h3><p> Not mentioned anywhere in the IBM documentation, but the existing JACC provider jar had to be copied into the <b>BundleContent</b> 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: <pre><br />Bundle-ClassPath: .,<br /> cdi-jacc-provider-0.1-SNAPSHOT.jar<br /></pre> 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: <div><a href="https://2.bp.blogspot.com/-gXbf3uFgyFU/V8S6pNjycbI/AAAAAAAAAc8/TplTF263uq8fPSXl2E8BKUrM4F3u4ySYwCLcB/s1600/java_build_path.png" imageanchor="1" ><img border="0" src="https://2.bp.blogspot.com/-gXbf3uFgyFU/V8S6pNjycbI/AAAAAAAAAc8/TplTF263uq8fPSXl2E8BKUrM4F3u4ySYwCLcB/s400/java_build_path.png" width="400" height="122" /></a></div> <p><h3>Implement a Liberty specific service that returns the policy and factory instances from our provider</h3><p> Contrary to all other servers, Liberty requires an amount of Liberty specific code in the module. The <a href="http://www.ibm.com/support/knowledgecenter/SSAW57_9.0.0/com.ibm.websphere.wlp.nd.doc/ae/twlp_developing_jacc_auth_provider.html">above mentioned instructions</a> 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 "<i>getPolicyConfigurationFactory</i>" method name was wrong (should be "<i>getPolicyConfigFactory</i>"), the return type of that same method was wrong (instead of "<i>Policy</i>" it should be "<i>PolicyConfigurationFactory</i>", then there's an <i>active</i> method that used a variable called "<i>configprops</i>" that's not defined anywhere, etc. <p>Additionally, the service uses the <i>@Component</i> 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: <p>[ERROR ] CWWKE0702E: Could not resolve module: JaccBundle [250] Unresolved requirement: Import-Package: org.osgi.service.component.annotations; version="1.3.0" </p> Being unable to resolve this, I removed the annotation and implemented a traditional <i>Activator</i> instead. The code for both the service and the activator is shown below: <p><b>Service:</b><pre class="brush: java;"><br />package jaccbundle;<br /><br />import static java.lang.System.setProperty;<br />import static java.lang.Thread.currentThread;<br /><br />import java.security.Policy;<br /><br />import javax.security.jacc.PolicyConfigurationFactory;<br /><br />import org.omnifaces.jaccprovider.jacc.policy.DefaultPolicy;<br /><br />import com.ibm.wsspi.security.authorization.jacc.ProviderService;<br /><br />public class MyJaccProviderService implements ProviderService {<br /> <br /> @Override<br /> public Policy getPolicy() {<br /> return new DefaultPolicy();<br /> }<br /><br /> @Override<br /> public PolicyConfigurationFactory getPolicyConfigFactory() {<br /> <br /> ClassLoader originalContextClassloader = <br /> currentThread().getContextClassLoader();<br /> try {<br /> currentThread()<br /> .setContextClassLoader(<br /> this.getClass().getClassLoader());<br /> <br /> setProperty(<br /> "javax.security.jacc.PolicyConfigurationFactory.provider",<br /> "org.omnifaces.jaccprovider.jacc.configuration.TestPolicyConfigurationFactory");<br /> <br /> return PolicyConfigurationFactory.getPolicyConfigurationFactory();<br /> } catch (Exception e) {<br /> return null;<br /> } finally {<br /> Thread.currentThread()<br /> .setContextClassLoader(<br /> originalContextClassloader);<br /> }<br /> }<br />}<br /></pre> <p><b>Activator</b><pre class="brush: java;"><br />package jaccbundle;<br /><br />import static org.osgi.framework.Constants.SERVICE_PID;<br /><br />import java.util.Hashtable;<br /><br />import org.osgi.framework.BundleActivator;<br />import org.osgi.framework.BundleContext;<br />import org.osgi.framework.ServiceRegistration;<br /><br />import com.ibm.wsspi.security.authorization.jacc.ProviderService;<br /><br />public class Activator implements BundleActivator {<br /> <br /> private static final String CONFIG_PID = "jaccBundle";<br /> private ServiceRegistration&lt;ProviderService&gt; jaccProviderService;<br /><br /> public void start(BundleContext context) throws Exception {<br /> jaccProviderService = context.registerService(<br /> ProviderService.class, <br /> new MyJaccProviderService(), <br /> getDefaults());<br /> }<br /><br /> public void stop(BundleContext context) throws Exception {<br /> if (jaccProviderService != null) {<br /> jaccProviderService.unregister();<br /> jaccProviderService = null;<br /> }<br /> }<br /><br /> Hashtable&lt;String, ?&gt; getDefaults() {<br /> Hashtable&lt;String, String&gt; defaults = new Hashtable&lt;&gt;();<br /> defaults.put(SERVICE_PID, CONFIG_PID);<br /> return defaults;<br /> }<br /><br />}<br /></pre><p><h3> Make sure we have the right imports and exports </h3><p> The Eclipse manifest editor offers a handy "Analyze code and add dependencies to the MANIFEST.FM" feature, but like the <a href="http://tfwiki.net/wiki/Matter_duplicator">matter duplicator</a> 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: <div><a href="https://4.bp.blogspot.com/-az0ugXimyCc/V8SsbYEA3OI/AAAAAAAAAcc/V-FLVJBTC-4omkC_QeT85VrUBCd6GVCxACLcB/s1600/imported_packages.png" imageanchor="1" ><img border="0" src="https://4.bp.blogspot.com/-az0ugXimyCc/V8SsbYEA3OI/AAAAAAAAAcc/V-FLVJBTC-4omkC_QeT85VrUBCd6GVCxACLcB/s400/imported_packages.png" width="400" height="212" /></a></div> <div><a href="https://4.bp.blogspot.com/-B3Qmfy_cEfg/V8SsjD2_PSI/AAAAAAAAAcg/Rp-qhwRkPQkxxcPcwXylgj6_J2ZZ0XQjACLcB/s1600/exported_packages.png" imageanchor="1" ><img border="0" src="https://4.bp.blogspot.com/-B3Qmfy_cEfg/V8SsjD2_PSI/AAAAAAAAAcg/Rp-qhwRkPQkxxcPcwXylgj6_J2ZZ0XQjACLcB/s400/exported_packages.png" width="400" height="201" /></a></div> <p>After some trial and error the MANIFEST.FM eventually looked like this: <div style="font-size:75%;"><pre><br />Manifest-Version: 1.0<br />Bundle-ManifestVersion: 2<br />Bundle-Name: JaccBundle<br />Bundle-SymbolicName: JaccBundle<br />Bundle-Version: 1.0.0.qualifier<br />Bundle-Activator: jaccbundle.Activator<br />Bundle-ClassPath: .,<br /> cdi-jacc-provider-0.1-SNAPSHOT.jar<br />Import-Package: com.ibm.wsspi.security.authorization.jacc;version="1.0.0",<br /> javax.enterprise.context;version="1.1.0",<br /> javax.enterprise.context.spi;version="1.1.0",<br /> javax.enterprise.inject;version="1.1.0",<br /> javax.enterprise.inject.spi;version="1.1.0",<br /> javax.inject;version="1.0.0",<br /> javax.naming,<br /> javax.security.auth,<br /> javax.security.jacc;version="1.5.0",<br /> org.osgi.framework<br />Bundle-RequiredExecutionEnvironment: JavaSE-1.8<br />Export-Package: jaccbundle,<br /> org.omnifaces.jaccprovider.cdi,<br /> org.omnifaces.jaccprovider.jacc<br /></pre></div> <p><h3>Create a Liberty Feature that references the previously created bundle and provides the right exports</h3><p> After having created the Liberty Feature project using the <a href="https://developer.ibm.com/wasdev/docs/create_your_own_simple_hello_world_user_feature">IBM instruction for the hello world feature</a>, there's relatively little to be done here. We do have to add the exports that we already exported from the bundle again here. <p>This can be done via the editor for the one and only file in our feature project called SUBSYSTEM.FM: <div><a href="https://2.bp.blogspot.com/-mJT_cIOJWPk/V8SnDX39daI/AAAAAAAAAcQ/bwJ9BN4-WOwc3Ou7TR1nyuJStx1cU2bxACLcB/s1600/liberty_feature_export.png" imageanchor="1" ><img border="0" src="https://2.bp.blogspot.com/-mJT_cIOJWPk/V8SnDX39daI/AAAAAAAAAcQ/bwJ9BN4-WOwc3Ou7TR1nyuJStx1cU2bxACLcB/s400/liberty_feature_export.png" width="400" height="170" /></a></div> The raw file will then look as follows: <div style="font-size:75%;"><pre><br />Subsystem-ManifestVersion: 1.0<br />IBM-Feature-Version: 2<br />IBM-ShortName: JaccFeature<br />Subsystem-SymbolicName: JaccFeature;visibility:=public<br />Subsystem-Version: 1.0.0.qualifier<br />Subsystem-Type: osgi.subsystem.feature<br />Subsystem-Content: JaccBundle;version="1.0.0"<br />Manifest-Version: 1.0<br />IBM-API-Package: org.omnifaces.jaccprovider.cdi,<br /> org.omnifaces.jaccprovider.jacc<br /></pre></div> The IBM JACC installation instructions mentioned one other point here: <blockquote>Ensure that your feature includes the OSGi subsystem content: com.ibm.ws.javaee.jacc.1.5; location:="dev/api/spec/". </blockquote> I could however not get this to work. Adding it to SUBSYSTEM.FM as follows: <pre><br />Subsystem-Content: JaccBundle;version="1.0.0",com.ibm.ws.javaee.jacc.1.5;location:="dev/api/spec/"<br /></pre> Resulted in the following error when starting Liberty: <pre><br />Bundle location:="dev/api/spec/" cannot be <br /> resolved<br /></pre> Adding it as: <pre><br />Subsystem-Content: JaccBundle;version="1.0.0",com.ibm.ws.javaee.jacc.1.5<br /></pre> Yielded the following error: <pre><br />[ERROR ] CWWKE0702E: Could not resolve module: com.ibm.ws.javaee.jacc.1.5 [251]<br /> 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"<br /></pre> Without this directive the JACC provider already worked as expected, so I just left it out. It's intended use is somewhat puzzling though. <p>The workspace with all artefacts combined for the two required projects looks as follows: <div><a href="https://1.bp.blogspot.com/-heI8Peeh4sM/V8S8EOHX64I/AAAAAAAAAdE/XDSxMlhp0hQEw5rFOVD-Ebu2nc09ZwkEACLcB/s1600/liberty_jacc_projects.png" imageanchor="1" ><img border="0" src="https://1.bp.blogspot.com/-heI8Peeh4sM/V8S8EOHX64I/AAAAAAAAAdE/XDSxMlhp0hQEw5rFOVD-Ebu2nc09ZwkEACLcB/s320/liberty_jacc_projects.png" width="312" height="320" /></a></div> <p><h3>Installing the feature in Liberty</h3> <p>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 <i>server.xml</i> file, for which there again is a graphical editor in Eclipse: <div><a href="https://3.bp.blogspot.com/-oNVkqQ9mDLY/V8SwwQ48RaI/AAAAAAAAAcw/zJB_Mo5J1hINOfaV69nntOC58apa4dnbwCLcB/s1600/liberty_features.png" imageanchor="1" ><img border="0" src="https://3.bp.blogspot.com/-oNVkqQ9mDLY/V8SwwQ48RaI/AAAAAAAAAcw/zJB_Mo5J1hINOfaV69nntOC58apa4dnbwCLcB/s400/liberty_features.png" width="400" height="184" /></a></div> <p>The raw file look as follows: <p><pre class="brush: xml;"><br />&lt;server description="Liberty beta"><br /><br /> &lt;featureManager><br /> &lt;feature>javaee-7.0&lt;/feature><br /> &lt;feature>localConnector-1.0&lt;/feature><br /> &lt;feature>usr:JaccFeature&lt;/feature><br /> &lt;/featureManager><br /><br /> &lt;httpEndpoint httpPort="8080" httpsPort="9443" id="defaultHttpEndpoint"/><br /> <br /> &lt;webContainer deferServletLoad="false"/><br /> &lt;ejbContainer startEJBsAtAppStart="true"/><br /><br /> &lt;applicationManager autoExpand="true"/><br /> &lt;applicationMonitor updateTrigger="mbean"/><br /><br />&lt;/server><br /></pre> <p>After this we can finally run a web application to test things, and it indeed seems to work as expected! <p>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). <p>The authorization mechanism as demonstrated in the <a href="http://arjan-tijms.omnifaces.org/2016/07/simplified-custom-authorization-rules.html">previous article</a> 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: <pre class="brush: java;"><br />Object weldInitialListener = request.getServletContext().getAttribute("org.jboss.weld.servlet.WeldInitialListener");<br />ServletRequestEvent event = new ServletRequestEvent(request.getServletContext(), request);<br /> <br />ELProcessor elProcessor = new ELProcessor();<br />elProcessor.defineBean("weldInitialListener", weldInitialListener);<br />elProcessor.defineBean("event", event);<br />elProcessor.eval("weldInitialListener.requestInitialized(event)");<br /></pre> 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 <p><h3>Conclusion</h3><p> 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. <p>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. <p>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. <p><i>Arjan Tijms</i> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com1tag:blogger.com,1999:blog-4498889353428710313.post-33026617857526651042016-07-23T13:21:00.000-07:002016-07-25T15:53:46.721-07:00Simplified custom authorization rules in Java EEIn a <a href="http://arjan-tijms.omnifaces.org/2015/03/java-ee-authorization-jacc-revisited.html">previous article</a> we looked at implementing a Java EE authorization module using the JACC specification. <a href="https://github.com/arjantijms/custom-authorization">This module</a> 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. <p>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 <small>(JACC doesn't have any code that can be reused, for the smallest change everything needs to be implemented from scratch)</small>, 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 <a href="http://adam-bien.com/roller/abien/entry/why_not_one_application_per">one application per server</a>, it's still quite a hassle to re-install the JACC provider after every little change separately from the application. <p>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 <a href="https://github.com/javaee-security-spec/soteria/blob/master/impl/src/main/java/org/glassfish/soteria/mechanisms/jaspic/HttpBridgeServerAuthModule.java#L90">the same thing</a> 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. <p>For the actual custom authorization rule we took inspiration from a rather interesting question and answer on StackOverflow:<br/> <br/> <b><a href="http://stackoverflow.com/q/27341665">Is it possible to determine group membership of a user on demand instead of when logging in via a ServerAuthModule (JASPIC)?</a></b> <p>As it appears, the answer to this question is <b>yes</b> ;) <p>In order to come to a solution for the above stated problem we first took the <a href="https://github.com/arjantijms/jacc-provider">original JACC provider</a> from the previous article and refactored it a little. The permissions that were previously put in the intermediate base class <a href="https://github.com/arjantijms/jacc-provider/blob/master/src/main/java/org/omnifaces/jaccprovider/TestPolicyConfigurationPermissions.java">TestPolicyConfigurationPermissions</a> were factored out to a separate struct like class: <pre class="brush: java;"><br />public class SecurityConstraints {<br /><br /> private Permissions excludedPermissions = new Permissions();<br /> private Permissions uncheckedPermissions = new Permissions();<br /> private Map&lt;String, Permissions&gt; perRolePermissions = new HashMap&lt;String, Permissions&gt;();<br /><br /> // + getters/setters<br /></pre> 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): <pre class="brush: java;"><br />public class Caller {<br /><br /> private Principal callerPrincipal;<br /> private List&lt;String&gt; roles;<br /> private List&lt;Principal&gt; unmappedPrincipals;<br /><br /> // + getters/setters<br /></pre> Next we define an interface for the application to implement. Our JACC provider will call this at certain points during the authorization process: <pre class="brush: java;"><br />public interface AuthorizationMechanism {<br /> <br /> default Boolean preAuthenticatePreAuthorize(Permission requestedPermission, SecurityConstraints securityConstraints) {<br /> return null;<br /> }<br /> <br /> default Boolean preAuthenticatePreAuthorizeByRole(Permission requestedPermission, SecurityConstraints securityConstraints) {<br /> return null;<br /> }<br /><br /> default Boolean postAuthenticatePreAuthorize(Permission requestedPermission, Caller caller, SecurityConstraints securityConstraints) {<br /> return null;<br /> }<br /> <br /> default Boolean postAuthenticatePreAuthorizeByRole(Permission requestedPermission, Caller caller, SecurityConstraints securityConstraints) {<br /> return null;<br /> }<br />}<br /></pre> 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. <small><i>(Note that methods have been used for now, but perhaps events are the better solution here)</i></small> <p>With these artefacts in place we can now modify the <a href="https://github.com/arjantijms/jacc-provider/blob/master/src/main/java/org/omnifaces/jaccprovider/TestPolicy.java">JACC Policy class</a> to request a bean via CDI that implements the <i>AuthorizationMechanism</i> interface, and if it exists call one of the appropriate methods. The following shows an excerpt of this: <pre class="brush: java;"><br />boolean postAuthenticate = domain.getPrincipals().length > 0;<br /><br />AuthorizationMechanism mechanism = getBeanReferenceExtra(AuthorizationMechanism.class);<br />Caller caller = null;<br /><br />if (postAuthenticate) {<br /> caller = new Caller(<br /> roleMapper.getCallerPrincipalFromPrincipals(currentUserPrincipals),<br /> roleMapper.getMappedRolesFromPrincipals(currentUserPrincipals),<br /> currentUserPrincipals);<br />}<br /><br />if (mechanism != null) {<br /> Boolean authorizationOutcome = postAuthenticate? <br /> mechanism.postAuthenticatePreAuthorize(requestedPermission, caller, securityConstraints) :<br /> mechanism.preAuthenticatePreAuthorize(requestedPermission, securityConstraints);<br /> <br /> if (authorizationOutcome != null) {<br /> return authorizationOutcome;<br /> }<br />}<br /></pre> <p>In the code above <i>getBeanReferenceExtra</i> uses CDI to fetch a bean of type <i>AuthorizationMechanism</i>. This method works around a bug in Payara where the so-called component namespaces aren't being set. This bug is pretty much <a href="https://java.net/jira/browse/GLASSFISH-21447">the same</a> 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 <i>postAuthenticatePreAuthorize</i> or the <i>preAuthenticatePreAuthorize</i> is called. <p>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). <p>For further details see the <a href="https://github.com/arjantijms/cdi-jacc-provider">full source code</a>. <p>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: <pre class="brush: java;"><br />@RequestScoped<br />public class CustomIdentityStore implements IdentityStore {<br /> <br /> public CredentialValidationResult validate(UsernamePasswordCredential usernamePasswordCredential) {<br /> <br /> if (usernamePasswordCredential.getCaller().equals("test") && <br /> usernamePasswordCredential.getPassword().compareTo("secret1")) {<br /> <br /> return new CredentialValidationResult(<br /> new CallerPrincipal("test"), <br /> null // no static groups, dynamically handled via authorization mechanism <br /> );<br /> }<br /> <br /> return INVALID_RESULT;<br /> }<br /> <br />}<br /></pre> We also add a custom JSR 375 <i>HttpAuthenticationMechanism</i>, one that's just used for testing purposes: <pre class="brush: java;"><br />@RequestScoped<br />public class CustomAuthenticationMechanism implements HttpAuthenticationMechanism {<br /> <br /> @Inject<br /> private IdentityStore identityStore;<br /><br /> @Override<br /> public AuthStatus validateRequest(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws AuthException {<br /><br /> if (request.getParameter("name") != null && request.getParameter("password") != null) {<br /><br /> CredentialValidationResult result = identityStore.validate(<br /> new UsernamePasswordCredential(request.getParameter("name"), request.getParameter("password")));<br /><br /> if (result.getStatus() == VALID) {<br /> return httpMessageContext.notifyContainerAboutLogin(<br /> result.getCallerPrincipal(), result.getCallerGroups());<br /> } else {<br /> throw new AuthException("Login failed");<br /> }<br /> } <br /><br /> return httpMessageContext.doNothing();<br /> }<br /> <br />}<br /></pre> 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 <i>HttpAuthenticationMechanism</i> is a CDI based HTTP specific variant of the <i>ServerAuthModule</i> that was mentioned in the SO question cited above. <p>Let's now finally look at our custom authorization rule, which basically looks as follows: <pre class="brush: java;"><br />@ApplicationScoped<br />public class CustomAuthorizationMechanism implements AuthorizationMechanism {<br /> <br /> @Override<br /> public Boolean postAuthenticatePreAuthorizeByRole(Permission requestedPermission, Caller caller, SecurityConstraints securityConstraints) {<br /> <br /> return getRequiredRoles(securityConstraints.getPerRolePermissions(), requestedPermission)<br /> .stream()<br /> .anyMatch(role -> isInRole(caller.getCallerPrincipal().getName(), role));<br /> }<br />}<br /></pre> 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 <i>WebResourcePermission</i> for a given protected path like <i>/foo/bar</i>. <p>In order to do the on demand membership check as was asked for in the SO question we start with using the <i>getRequiredRoles</i> method and the <a href="http://arjan-tijms.omnifaces.org/2015/04/how-java-ee-translates-webxml.html">collected</a> <i>SecurityConstraints</i> 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 <i>isInRole</i> 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". <p>For completeness, the <i>getRequiredRoles</i> method gets the roles that are required for a requested permission as follows: <pre class="brush: java;"><br />return perRolePermissions<br /> .entrySet().stream()<br /> .filter(entry -> entry.getValue().implies(requestedPermission))<br /> .map(e -> e.getKey())<br /> .collect(toList());<br /></pre> In order to test if the authorization rule works we add a protected Servlet as follows: <pre class="brush: java;"><br />@DeclareRoles({ "foo", "bar", "kaz" })<br />@WebServlet("/protected/servlet")<br />@ServletSecurity(@HttpConstraint(rolesAllowed = "foo"))<br />public class ProtectedServlet extends HttpServlet {<br /><br /> private static final long serialVersionUID = 1L;<br /><br /> @Override<br /> public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br /><br /> response.getWriter().write("This is a protected servlet \n");<br /><br /> String webName = null;<br /> if (request.getUserPrincipal() != null) {<br /> webName = request.getUserPrincipal().getName();<br /> }<br /><br /> response.getWriter().write("web username: " + webName + "\n");<br /><br /> response.getWriter().write("web user has role \"foo\": " + request.isUserInRole("foo") + "\n");<br /> response.getWriter().write("web user has role \"bar\": " + request.isUserInRole("bar") + "\n");<br /> response.getWriter().write("web user has role \"kaz\": " + request.isUserInRole("kaz") + "\n");<br /> }<br /><br />}<br /></pre> The Servlet shown here is protected by the role "foo", so with the above given <i>IdentityStore</i> 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". <p>Next we added a <i>preAuthenticatePreAuthorize</i> method to our authorization mechanism with some logging and also added logging to our existing <i>postAuthenticatePreAuthorizeByRole</i> method. We then deployed the application as "custom-authorization" to Payara 4.1.1.162 and requested <i>http://localhost:8080/custom-authorization/protected/servlet?name=test&password=secret1</i>. This resulted in the following log entries: <small><small><pre><br />preAuthenticatePreAuthorize called. Requested permission: ("javax.security.jacc.WebUserDataPermission" "/protected/servlet" "GET")<br />preAuthenticatePreAuthorize called. Requested permission: ("javax.security.jacc.WebResourcePermission" "/protected/servlet" "GET")<br /><br />validateRequest called. Authentication mandatory: true<br /><br />postAuthenticatePreAuthorizeByRole called. Requested permission: ("javax.security.jacc.WebResourcePermission" "/protected/servlet" "GET")<br /><br />postAuthenticatePreAuthorizeByRole called. Requested permission: ("javax.security.jacc.WebRoleRefPermission" "org.omnifaces.authorization.ProtectedServlet" "foo")<br />postAuthenticatePreAuthorizeByRole called. Requested permission: ("javax.security.jacc.WebRoleRefPermission" "org.omnifaces.authorization.ProtectedServlet" "bar")<br />postAuthenticatePreAuthorizeByRole called. Requested permission: ("javax.security.jacc.WebRoleRefPermission" "org.omnifaces.authorization.ProtectedServlet" "kaz")<br /></pre></small></small> 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. <p>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 <i>WebResourcePermission</i> 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". <p>We therefor continue to our requested resource, which means the servlet will be invoked. <p>Interesting to note here is that <i>HttpServletRequest#isUserInRole</i> is <b>not</b> 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 <i>isUserInRole</i> 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. <p>Also interesting to note is that our authorization mechanism handles a requested permission to access "/protected/servlet" and a requested permission for <i>isUserInRole("foo")</i> completely identical. If necessary the authorization mechanism can of course inspect the requested permission, but for this use case that wasn't necessary. <p>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: <small><small><pre><br />preAuthenticatePreAuthorize called. Requested permission: ("javax.security.jacc.WebUserDataPermission" "/public/servlet" "GET")<br />preAuthenticatePreAuthorize called. Requested permission: ("javax.security.jacc.WebResourcePermission" "/public/servlet" "GET")<br /><br />validateRequest called. Authentication mandatory: false<br /><br />postAuthenticatePreAuthorizeByRole called. Requested permission: ("javax.security.jacc.WebRoleRefPermission" "org.omnifaces.authorization.PublicServlet" "foo")<br />postAuthenticatePreAuthorizeByRole called. Requested permission: ("javax.security.jacc.WebRoleRefPermission" "org.omnifaces.authorization.PublicServlet" "bar")<br />postAuthenticatePreAuthorizeByRole called. Requested permission: ("javax.security.jacc.WebRoleRefPermission" "org.omnifaces.authorization.PublicServlet" "kaz")<br /></pre></small></small> 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. <p>For more details see the <a href="https://github.com/arjantijms/custom-authorization">full source code</a> of the example application. <p> <h3> Conclusion </h3><p> 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. <p>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. <p>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). <p><i>Arjan Tijms</i> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com2tag:blogger.com,1999:blog-4498889353428710313.post-72326974216652191562016-06-03T16:53:00.000-07:002016-06-05T02:15:55.465-07:00The state of portable authentication in Java EE, mid 2016 updateIn the <a href="http://arjan-tijms.omnifaces.org/2016/01/latest-versions-payara-and-wildfly.html">beginning of this year</a> and <a href="http://arjan-tijms.omnifaces.org/2015/11/the-state-of-portable-authentication.html">two months prior to that</a> 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. <p><a href="http://arjan-tijms.omnifaces.org/2012/11/implementing-container-authentication.html">Originally</a> 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 <a href="https://github.com/javaee-samples/javaee7-samples/commit/b4bfc05be0da73239e000df14eee7b6fee499bfe">registering a session with a custom principal</a> and <a href="https://github.com/javaee-samples/javaee7-samples/commit/e7a3b436d98a7be794a530465db2e9072362837c">EJB propagation after register session</a>. <p>The results of running the <a href="https://github.com/javaee-samples/javaee7-samples/tree/master/jaspic">latest series of JASPIC tests</a> are shown below: <p><div style="font-size:75%;"><table border="1"><caption>Running the Java EE 7 samples JASPIC tests</caption><tr style="background-color:LightGray"> <th>Module</th> <th>Test</th> <th>Payara 4.1.1.163 snapshot</th> <th>WildFly 10.0.0</th> <th>Liberty 9 beta 2016.5</th> <th>TomEE 7.0.0</th></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/async-authentication">async-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/async-authentication/src/test/java/org/javaee7/jaspic/asyncauthentication/AsyncAuthenticationPublicTest.java">testBasicAsync</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationProtectedTest.java">testProtectedPageNotLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationProtectedTest.java">testProtectedPageLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationPublicTest.java">testPublicPageLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationPublicTest.java">testPublicPageNotLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedAccessIsStateless2</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedThenPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalProtectedTest.java">testProtectedPageLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalPublicTest.java">testPublicPageLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedAccessIsStateless2</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedThenPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicForwardTest.java">testBasicForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicForwardTest.java">testBasicForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicIncludeTest.java">testBasicIncludeViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIForwardTest.java">testCDIForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIForwardTest.java">testCDIForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIIncludeTest.java">testCDIIncludeViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFCDIForwardTest.java">testJSFwithCDIForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFCDIForwardTest.java">testJSFwithCDIForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFCDIIncludeTest.java">testJSFwithCDIIncludeViaPublicResource</a></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFForwardTest.java">testJSFForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFForwardTest.java">testJSFForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFIncludeTest.java">testJSFIncludeViaPublicResource</a></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/ProtectedEJBPropagationTest.java">publicServletCallingProtectedEJB</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/ProtectedEJBPropagationTest.java">protectedServletCallingProtectedEJB</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/PublicEJBPropagationLogoutTest.java">publicServletCallingPublicEJBThenLogout</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/PublicEJBPropagationTest.java">protectedServletCallingPublicEJB</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromSecureResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for secureResponse for protected resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromValidateRequest</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for validateRequest for protected resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromSecureResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for secureResponse for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromValidateRequest</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for validateRequest for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromSecureResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromValidateRequest</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromSecureResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromValidateRequest</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation">jacc-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation/src/test/java/org/javaee7/jaspic/jaccpropagation/JACCPropagationProtectedTest.java">callingJACCWhenAuthenticated</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Did not have access to protected servlet from within that Servlet. Perhaps the roles did not propogate from JASPIC to JACC and the server didn't use JACC to grant access to invoking said Servlet?">Failure</div></td> <td bgcolor="LightCoral"><div title="JACC doesn't seem to be available.">Failure</div></td> <td bgcolor="LightCoral"><div title="JACC doesn't seem to be available.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation">jacc-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation/src/test/java/org/javaee7/jaspic/jaccpropagation/JACCPropagationPublicTest.java">callingJACCWhenAuthenticated</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Did not have access to protected servlet from within public servlet. Perhaps the roles did not propogate from JASPIC to JACC?">Failure</div></td> <td bgcolor="LightCoral"><div title="JACC doesn't seem to be available.">Failure</div></td> <td bgcolor="LightCoral"><div title="JACC doesn't seem to be available.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation">jacc-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation/src/test/java/org/javaee7/jaspic/jaccpropagation/JACCPropagationPublicTest.java">callingJACCWhenNotAuthenticated</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="JACC doesn't seem to be available.">Failure</div></td> <td bgcolor="LightCoral"><div title="JACC doesn't seem to be available.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle">lifecycle</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle/src/test/java/org/javaee7/jaspic/lifecycle/AuthModuleMethodInvocationTest.java">testBasicSAMMethodsCalled</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle">lifecycle</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle/src/test/java/org/javaee7/jaspic/lifecycle/AuthModuleMethodInvocationTest.java">testLogout</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionCustomPrincipalEJBPropagationTest.java">testRemembersSessionEJB</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Web has user principal set, but EJB not.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionCustomPrincipalTest.java">testJoinSessionIsOptional</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Could not access public page, but should be able to. Does the container have an automatic session fixation prevention?">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionCustomPrincipalTest.java">testRemembersSession</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionEJBPropagationTest.java">testRemembersSessionEJB</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Web has user principal set, but EJB not.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionTest.java">testJoinSessionIsOptional</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Could not access public page, but should be able to. Does the container have an automatic session fixation prevention?">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionTest.java">testRemembersSession</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes">status-codes</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes/src/test/java/org/javaee7/jaspic/statuscodes/ProtectedStatusCodesTest.java">test404inResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes">status-codes</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes/src/test/java/org/javaee7/jaspic/statuscodes/PublicStatusCodesTest.java">test404inResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping">wrapping</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping/src/test/java/org/javaee7/jaspic/wrapping/WrappingTest.java">testResponseWrapping</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping">wrapping</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping/src/test/java/org/javaee7/jaspic/wrapping/WrappingTest.java">testRequestWrapping</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr></table></div> <p> Not directly shown in the table, but one of the biggest changes is that <a href="https://developer.ibm.com/wasdev/blog/2016/06/03/beta-websphere-liberty-and-tools-june-2016/">Liberty 9 beta 2016.5</a> 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 <a href="http://arjan-tijms.omnifaces.org/2015/10/how-servlet-containers-all-implement.html">identity store</a>). 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. <p>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 <small>(<i>with a caveat for GlassFish that by default it does require group to role mapping</i>)</small>. 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 (<i>ibm-application-bnd.xml</i>), 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. <p>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 <i>&lt;httpSession securityIntegrationEnabled="false"/&gt</i> in server.xml. <p>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. <p>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 href="https://issues.jboss.org/browse/WFLY-5739">a bug</a> prevents roles to be propagated correctly). Additionally, <a href="https://issues.jboss.org/browse/WFLY-6579">a new bug</a> 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). <p>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. <p><h3>Conclusion</h3> <p>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. <p>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) <p><i>Arjan Tijms</i>Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com9tag:blogger.com,1999:blog-4498889353428710313.post-83470445464144065742016-05-04T06:02:00.000-07:002016-05-05T02:30:02.870-07:00Java EE's mysterious message policyUsers of Java EE authentication (JASPIC) may have noticed that the <a href="https://docs.oracle.com/javaee/7/api/javax/security/auth/message/module/ServerAuthModule.html#initialize-javax.security.auth.message.MessagePolicy-javax.security.auth.message.MessagePolicy-javax.security.auth.callback.CallbackHandler-java.util.Map-">initialize method</a> of a SAM takes two parameters of type <a href="https://docs.oracle.com/javaee/7/api/javax/security/auth/message/MessagePolicy.html">MessagePolicy</a>. But what are these parameters used for? In this article we'll take a somewhat deeper look. <p>In practice, the overwhelming majority of SAMs only seem to use this <i>MessagePolicy</i> 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. <p>The JASPIC spec isn't quite clear about this either. It does seem to say in a somewhat cryptic way that the <a href="https://docs.oracle.com/javaee/7/api/javax/security/auth/message/MessagePolicy.html#isMandatory--">isMandatory</a> method is an alias for the <i>"javax.security.auth.message.MessagePolicy.isMandatory"</i> entry in the <i>MessageInfo</i> map, and that the <a href="https://docs.oracle.com/javaee/7/api/javax/security/auth/message/MessagePolicy.ProtectionPolicy.html">ProtectionPolicy</a> of the <a href="https://docs.oracle.com/javaee/7/api/javax/security/auth/message/MessagePolicy.TargetPolicy.html">TargetPolicy</a> of the <a href="https://docs.oracle.com/javaee/7/api/javax/security/auth/message/MessagePolicy.html">MessagePolicy</a> must be <a href="https://docs.oracle.com/javaee/7/api/javax/security/auth/message/MessagePolicy.ProtectionPolicy.html#AUTHENTICATE_SENDER">ProtectionPolicy.AUTHENTICATE_SENDER</a> and/or <a href="https://docs.oracle.com/javaee/7/api/javax/security/auth/message/MessagePolicy.ProtectionPolicy.html#AUTHENTICATE_CONTENT">ProtectionPolicy.AUTHENTICATE_CONTENT</a>. <p>Pretty much the only example we have in code that at least references the <i>MessagePolicy</i> 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 <i>domain.xml</i> as follows: <pre class="brush: xml;"><br />&lt;message-security-config auth-layer="HttpServlet"&gt;<br /> &lt;provider-config provider-type="server" <br /> provider-id="GFConsoleAuthModule"<br /> class-name="org.glassfish.admingui.common.security.AdminConsoleAuthModule"&gt;<br /> &lt;request-policy auth-source="sender"/&gt<br /> &lt;response-policy/&gt<br /> &lt;property name="loginPage" value="/login.jsf"/&gt<br /> &lt;property name="loginErrorPage" value="/loginError.jsf"/&gt<br /> &lt;/provider-config&gt;<br />&lt;/message-security-config&gt;<br /></pre> <p>Unfortunately, despite a minimal request policy being configured here, the actual implementation of AdminConsoleAuthModule does the same thing that basically all other SAMs do: <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.glassfish.main.admingui/console-common/4.1/org/glassfish/admingui/common/security/AdminConsoleAuthModule.java#132">ignore it</a>. <p>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, <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.glassfish.main.security/websecurity/4.1/com/sun/web/security/RealmAdapter.java#1626">when the runtime calls the <i>validateRequest</i> method</a> of the encapsulating context. In order to make things readable for this article, I removed all alternative branches in the code <small>(mostly permutations of client/server modules and new/old modules (new = jaspic, old = the GlassFish proprietary predecessor of JASPIC) and Servlet/SOAP)</small>. With those branches removed and flattening the code found in many helper methods and contained objects, it looks as follows: <pre class="brush: java;"><br />// Check if the resource is secured and put as string in Map<br />isMandatory = !webSecMgr.permitAll(req);<br />if (isMandatory || calledFromAuthenticate) {<br /> messageInfo.getMap().put(IS_MANDATORY, TRUE.toString());<br />}<br /><br />// Get “true” / “false” string from map, convert it to Boolean and then to string again<br />String isMandatoryStr = messageInfo.getMap().get(IS_MANDATORY);<br />String authContextID = Boolean.valueOf(isMandatoryStr).toString();<br /><br />// Convert once again to Boolean, and set to MANDATORY or OPTIONAL policy<br />messagePolicy = Boolean.valueOf(authContextID)? <br /> new MessagePolicy[] { MANDATORY_POLICY, null } : // response policy always null<br /> new MessagePolicy[] { OPTIONAL_POLICY, null }<br /><br />IDEntry idEntry = configMap.get(“HttpServlet”).idMap.get(providerID);<br /><br />// Set the definite request policy, but messagePolicy[0] is never null here<br />// for the “HttpServlet” layer<br />MessagePolicy requestPolicy = (messagePolicy[0] != null || messagePolicy[1] != null)?<br /> messagePolicy[0] : // will always be chosen here <br /> idEntry.requestPolicy; // the policy as parsed from domain.xml, always unused <br /> <br />Entry entry = new Entry(idEntry.moduleClassName, requestPolicy, idEntry.options);<br /><br />// Pass the message policies into the SAM instance<br />ServerAuthModule sam = entry.newInstance();<br />sam.initialize(<br /> entry.getRequestPolicy(),<br /> entry.getResponsePolicy(), handler, map);<br /><br />ModuleInfo moduleInfo = ModuleInfo(sam, map);<br /><br />ServerAuthModule moduleObj = moduleInfo.getModule();<br />Map moduleMap = moduleInfo.getMap();<br /> <br />ServerAuthContext serverAuthContext = new GFServerAuthContext(moduleObj, moduleMap);<br /><br />// Invoke the context, which on its turn will invoke the SAM we just initialized <br />AuthStatus authStatus = serverAuthContext.validateRequest(messageInfo, subject, null);<br /></pre> <p>As can be seen, despite there being a path for setting the parsed request policy from <i>domain.xml</i> (the <i>idEntry.requestPolicy</i>), the code always chooses between one of two fixed policies; <i>MANDATORY_POLICY</i> or <i>OPTIONAL_POLICY</i>, depending on the same <i>IS_MANDATORY</i> value (<i>"javax.security.auth.message.MessagePolicy.isMandatory"</i>) that is put in the message info map. <p>Those two fixed policies are set as static final variables as follows: <pre class="brush: java;"><br />private static final MessagePolicy MANDATORY_POLICY =<br /> getMessagePolicy(true);<br /> <br />private static final MessagePolicy OPTIONAL_POLICY =<br /> getMessagePolicy(false);<br /></pre> Where the <i>getMessagePolicy()</i> method has the following relevant content (code branches that were never taken have been cut out again): <pre class="brush: java;"><br />public static MessagePolicy getMessagePolicy (boolean mandatory) {<br /> <br /> List&lt;TargetPolicy> targetPolicies = new ArrayList&lt;TargetPolicy>();<br /> <br /> targetPolicies.add(new TargetPolicy(<br /> null, // No Target<br /> new ProtectionPolicy() {<br /> public String getID() {<br /> return ProtectionPolicy.AUTHENTICATE_SENDER;<br /> } <br /> })<br /> );<br /> <br /> return new MessagePolicy(<br /> targetPolicies.toArray(new TargetPolicy[targetPolicies.size()]),<br /> mandatory);<br />}<br /></pre> <h3>Conclusion</h3> <p>The conclusion seems to be, assuming that the RI code is as spec compliant as we can get, that <i>MessagePolicy#isMandatory()</i> is just an alternative for <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.glassfish.main.admingui/console-common/4.1/org/glassfish/admingui/common/security/AdminConsoleAuthModule.java#342">checking the message info map</a>, 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 <a href="http://arjan-tijms.omnifaces.org/2012/11/implementing-container-authentication.html">registered programmatically</a>, the entire initialization of the SAM is under the application's control and the behavior of the server doesn't apply. <p>Speculating, it might be the case that <i>AUTHENTICATE_SENDER</i> simply means "do what a SAM is supposed to do in validateRequest()" (e.g. authenticating callers), while the potential alternative or additional <i>AUTHENTICATE_CONTENT</i> 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 <i>AUTHENTICATE_CONTENT</i> and <i>isMandatory()</i> returning <i>true</i> 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. <p>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. <p><i>Arjan Tijms</i> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com1tag:blogger.com,1999:blog-4498889353428710313.post-21488370297421674962016-04-02T14:08:00.000-07:002016-04-02T14:14:46.278-07:00Servlet 4.0's mapping API previewed in Tomcat 9.0 m4Without 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 <a href="http://arjan-tijms.omnifaces.org/2015/03/the-most-popular-java-ee-servers-in.html">one of the most frequently used</a> standalone Servlet containers. <p>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 <a href="https://java.net/projects/javaee-spec/lists/users/archive/2016-03/message/11">is working on other assignments</a> and hasn't worked out a schedule to incorporate this new functionality. <p>Luckily Tomcat has taken the initiative and in <a href="http://tomcat.apache.org/download-90.cgi#9.0.0.M4">Tomcat 9.0.0.M4</a> the <a href="https://java.net/projects/servlet-spec/lists/jsr369-experts/archive/2015-09/message/21">proposed</a> Servlet 4.0 <a href="https://java.net/jira/browse/SERVLET_SPEC-73">Mapping API</a> has been implemented. <p>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 <i>"/foo/*"</i> and <i>"*.bar"</i> 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. <p>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 <i>HttpServletRequest#getMapping()</i> method: <pre class="brush: java;"><br />public default Mapping getMapping() {<br /> // ...<br />}<br /></pre> The new <i>Mapping</i> type that can be seen in the signature of the above method looks as follows: <div style="font-size:90%;"><pre class="brush: java;"><br />/**<br /> * Represents how the request from which this object was obtained was mapped to<br /> * the associated servlet.<br /> *<br /> * @since 4.0<br /> */<br />public interface Mapping {<br /><br /> /**<br /> * @return The value that was matched or the empty String if not known.<br /> */<br /> String getMatchValue();<br /><br /> /**<br /> * @return The {@code url-pattern} that matched this request or the empty<br /> * String if not known.<br /> */<br /> String getPattern();<br /><br /> /**<br /> * @return The type of match ({@link MappingMatch#UNKNOWN} if not known)<br /> */<br /> MappingMatch getMatchType();<br />}<br /></pre></div> The <i>MappingMatch</i> is an enumeration of the different types of possible mappings as shown below: <div style="font-size:90%;"><pre class="brush: java;"><br />/**<br /> * Represents the ways that a request can be mapped to a servlet<br /> *<br /> * @since 4.0<br /> */<br />public enum MappingMatch {<br /><br /> CONTEXT_ROOT,<br /> DEFAULT,<br /> EXACT,<br /> EXTENSION,<br /> IMPLICIT,<br /> PATH,<br /> UNKNOWN<br />}<br /></pre></div> To test out the new functionality the following test Servlet was used: <div style="font-size:90%;"><pre class="brush: java;"><br />@WebServlet({"/path/*", "*.ext", "", "/", "/exact"})<br />public class Servlet extends HttpServlet {<br /> <br /> private static final long serialVersionUID = 1L;<br /><br /> protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br /> <br /> Mapping mapping = request.getMapping();<br /> <br /> response.getWriter()<br /> .append("Mapping match:")<br /> .append(mapping.getMatchType().name())<br /> .append("\n")<br /> .append("Match value:")<br /> .append(mapping.getMatchValue())<br /> .append("\n")<br /> .append("Pattern:")<br /> .append(mapping.getPattern());<br /> }<br /><br />}<br /></pre></div> <p>As can be seen this Servlet is mapped via a path mapping (<i>"/path/*"</i>), extension mapping (<i>"*.ext"</i>), context root mapping (<i>""</i>), default mapping (<i>"/"</i>) 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: <p><b>Path mapping</b><br/><i>http://localhost:8080/servlet4/path/foo</i> <pre><br />Mapping match:PATH<br />Match value:/foo<br />Pattern:/path/*<br /></pre> <p><b>Extension mapping</b><br/><i>http://localhost:8080/servlet4/foo.ext</i> <pre><br />Mapping match:EXTENSION<br />Match value:/foo<br />Pattern:*.ext<br /></pre> <p><b>Context root mapping</b><br/><i>http://localhost:8080/servlet4</i> <pre><br />Mapping match:CONTEXT_ROOT<br />Match value:<br />Pattern:<br /></pre> <p><b>Default (fallback) mapping</b><br/><i>http://localhost:8080/servlet4/doesnotexist</i> <pre><br />Mapping match:DEFAULT<br />Match value:/<br />Pattern:/<br /></pre> <p><b>Exact mapping</b><br/><i>http://localhost:8080/servlet4/exact</i> <pre><br />Mapping match:EXACT<br />Match value:/exact<br />Pattern:/exact<br /></pre> To test the implicit mapping (as per Servlet spec 12.2.1), the following JSP file was used: <div style="font-size:90%;"><pre class="brush: java;"><br />&lt;%<br />Mapping mapping = request.getMapping();<br /><br />response.getWriter()<br /> .append("Mapping match:")<br /> .append(mapping.getMatchType().name())<br /> .append("\n")<br /> .append("Match value:")<br /> .append(mapping.getMatchValue())<br /> .append("\n")<br /> .append("Pattern:")<br /> .append(mapping.getPattern());<br />%&gt;<br /></pre></div> This was however seen by Tomcat as a regular extension mapping: <p><b>Implicit mapping</b><br/><i>http://localhost:8080/servlet4/page.jsp</i> <pre><br />Mapping match:EXTENSION <br />Match value:/page <br />Pattern:*.jsp<br /></pre> 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"? <p><h3>Conclusion</h3> <p>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. <p><i>Arjan Tijms</i> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com8tag:blogger.com,1999:blog-4498889353428710313.post-16510079789634003432016-01-18T16:17:00.001-08:002016-01-18T16:17:17.178-08:00Java EE 7 server Liberty 9 beta 2016.1 tested for JASPIC supportIBM recently released the latest monthly beta of their modern and light weight Java EE 7 server; <a href="https://developer.ibm.com/wasdev/blog/2016/01/15/beta-websphere-liberty-and-tools-january">Liberty 9 beta 2016.1</a>. 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. <p>In this article we take a look to see if JASPIC support has improved in the latest release. To find out we executed <a href="https://github.com/javaee-samples/javaee7-samples/tree/master/jaspic">the JASPIC tests</a> against this latest release. For comparison the previous Liberty beta as well as the latest (snapshots) of Payara and WildFly are shown. <p>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 <a href="https://developer.ibm.com/wasdev/downloads/liberty-profile-beta">the download page</a>, as the size that as stated (116 mb) is not the same as the actual archive that's downloaded (94 mb). <p>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: <pre><br />bin/installUtility install javaee-7.0<br /></pre> 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: <pre><br />bin/installUtility install localConnector-1.0<br /></pre> <p>After this we could run the tests. The results are shown in the table below: <p> <div style="font-size:75%;"><table border="1"><caption>Running the Java EE 7 samples JASPIC tests</caption> <tr style="background-color:LightGray"> <th>Module</th> <th>Test</th> <th>Payara 4.1.1.161-pre</th> <th>WildFly 10rc5</th> <th>Liberty 9 beta 2016.1</th> <th>Liberty 9 beta 2015.11</th></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/async-authentication">async-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/async-authentication/src/test/java/org/javaee7/jaspic/asyncauthentication/AsyncAuthenticationPublicTest.java">testBasicAsync</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationProtectedTest.java">testProtectedPageNotLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationProtectedTest.java">testProtectedPageLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationPublicTest.java">testPublicPageLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationPublicTest.java">testPublicPageNotLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedAccessIsStateless2</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedThenPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalProtectedTest.java">testProtectedPageLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalPublicTest.java">testPublicPageLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedAccessIsStateless2</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedThenPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicForwardTest.java">testBasicForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicForwardTest.java">testBasicForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicIncludeTest.java">testBasicIncludeViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from target Servlet after included one.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIForwardTest.java">testCDIForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIForwardTest.java">testCDIForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIIncludeTest.java">testCDIIncludeViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from target Servlet after included one.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFCDIForwardTest.java">testJSFwithCDIForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFCDIForwardTest.java">testJSFwithCDIForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFCDIIncludeTest.java">testJSFwithCDIIncludeViaPublicResource</a></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFForwardTest.java">testJSFForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFForwardTest.java">testJSFForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFIncludeTest.java">testJSFIncludeViaPublicResource</a></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/ProtectedEJBPropagationTest.java">publicServletCallingProtectedEJB</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/ProtectedEJBPropagationTest.java">protectedServletCallingProtectedEJB</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/PublicEJBPropagationLogoutTest.java">publicServletCallingPublicEJBThenLogout</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/PublicEJBPropagationTest.java">protectedServletCallingPublicEJB</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromSecureResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for secureResponse for protected resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for secureResponse for protected resource. (note: this is not required by the spec)">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromValidateRequest</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for validateRequest for protected resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for validateRequest for protected resource. (note: this is not required by the spec)">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromSecureResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for secureResponse for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for secureResponse for public resource. (note: this is not required by the spec)">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromValidateRequest</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for validateRequest for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for validateRequest for public resource. (note: this is not required by the spec)">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for cleanSubject for public resource. (note: this is not required by the spec)">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromSecureResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromValidateRequest</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromSecureResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromValidateRequest</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation">jacc-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation/src/test/java/org/javaee7/jaspic/jaccpropagation/JACCPropagationProtectedTest.java">callingJACCWhenAuthenticated</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Did not have access to protected servlet from within that Servlet. Perhaps the roles did not propogate from JASPIC to JACC and the server didn't use JACC to grant access to invoking said Servlet?">Failure</div></td> <td bgcolor="LightCoral"><div title="JACC doesn't seem to be available.">Failure</div></td> <td bgcolor="LightCoral"><div title="JACC doesn't seem to be available.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation">jacc-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation/src/test/java/org/javaee7/jaspic/jaccpropagation/JACCPropagationPublicTest.java">callingJACCWhenAuthenticated</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Did not have access to protected servlet from within public servlet. Perhaps the roles did not propogate from JASPIC to JACC?">Failure</div></td> <td bgcolor="LightCoral"><div title="JACC doesn't seem to be available.">Failure</div></td> <td bgcolor="LightCoral"><div title="JACC doesn't seem to be available.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation">jacc-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation/src/test/java/org/javaee7/jaspic/jaccpropagation/JACCPropagationPublicTest.java">callingJACCWhenNotAuthenticated</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="JACC doesn't seem to be available.">Failure</div></td> <td bgcolor="LightCoral"><div title="JACC doesn't seem to be available.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle">lifecycle</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle/src/test/java/org/javaee7/jaspic/lifecycle/AuthModuleMethodInvocationTest.java">testBasicSAMMethodsCalled</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle">lifecycle</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle/src/test/java/org/javaee7/jaspic/lifecycle/AuthModuleMethodInvocationTest.java">testLogout</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionTest.java">testJoinSessionIsOptional</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionTest.java">testRemembersSession</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes">status-codes</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes/src/test/java/org/javaee7/jaspic/statuscodes/ProtectedStatusCodesTest.java">test404inResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes">status-codes</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes/src/test/java/org/javaee7/jaspic/statuscodes/PublicStatusCodesTest.java">test404inResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping">wrapping</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping/src/test/java/org/javaee7/jaspic/wrapping/WrappingTest.java">testResponseWrapping</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping">wrapping</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping/src/test/java/org/javaee7/jaspic/wrapping/WrappingTest.java">testRequestWrapping</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> </table></div> <p>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. <p>Additionally one CDI problem was fixed; obtaining and invoking a CDI bean from a SAM's <i>cleanSubject</i> method. This already worked on previous betas when the request was to a protected resource, but mysteriously failed for public resources. The <i>cleanSubject</i> method is generally somewhat easier to support, as this method is called in response to <i>HttpServletRequest#logout</i> 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). <p>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 <i>validateRequest</i> and <i>secureResponse</i> methods. Unfortunately early versions of the JSR 375 API can now not be tested on Liberty. <h3>Conclusion</h3><p> 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. <p><i>Arjan Tijms</i> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com0tag:blogger.com,1999:blog-4498889353428710313.post-36828236499185649802016-01-06T15:23:00.000-08:002016-01-07T12:29:51.607-08:00Latest versions Payara and WildFly improve Java EE 7 authentication complianceTwo months ago we looked at the <a href="http://arjan-tijms.omnifaces.org/2015/11/the-state-of-portable-authentication.html">state of portable authentication for GlassFish, Payara, JBoss/WildFly, WebLogic and Liberty</a> 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. <p>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 <a href="http://www.payara.fish/upstream_builds">pre-release</a> resp. <a href="http://wildfly.org/downloads">rc/cr</a> builds containing those fixes can be downloaded from the vendors. <p>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. <small><i>(no less than 29 builds were released for WildFly 8,9,10/EAP 7 alpha,beta)</i></small>. <p> <div style="font-size:75%;"><table border="1"><caption>Running the Java EE 7 samples JASPIC tests</caption><tr style="background-color:LightGray"> <th>Module</th> <th>Test</th> <th>Payara 4.1.1.161-pre</th> <th>GlassFish 4.1.1</th> <th>WildFly 10rc5</th> <th>WildFly 10rc4</th> <th>WildFly 9.0.1</th> <th>WildFly 8.0.0</th></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/async-authentication">async-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/async-authentication/src/test/java/org/javaee7/jaspic/asyncauthentication/AsyncAuthenticationPublicTest.java">testBasicAsync</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Read timed out">Failed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationProtectedTest.java">testProtectedPageNotLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationProtectedTest.java">testProtectedPageLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationPublicTest.java">testPublicPageLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationPublicTest.java">testPublicPageNotLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedAccessIsStateless2</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedThenPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalProtectedTest.java">testProtectedPageLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Authentication succeeded and username and roles are correct, but principal type is not the expected custom type.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalPublicTest.java">testPublicPageLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Username and roles are correct, but principal type is not the expected custom type.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedAccessIsStateless2</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedThenPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicForwardTest.java">testBasicForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicForwardTest.java">testBasicForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicIncludeTest.java">testBasicIncludeViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from target Servlet after included one.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIForwardTest.java">testCDIForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIForwardTest.java">testCDIForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIIncludeTest.java">testCDIIncludeViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from target Servlet after included one.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFCDIForwardTest.java">testJSFwithCDIForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFCDIForwardTest.java">testJSFwithCDIForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFCDIIncludeTest.java">testJSFwithCDIIncludeViaPublicResource</a></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFForwardTest.java">testJSFForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFForwardTest.java">testJSFForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFIncludeTest.java">testJSFIncludeViaPublicResource</a></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/ProtectedEJBPropagationTest.java">publicServletCallingProtectedEJB</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Web has user principal set, but EJB not.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/ProtectedEJBPropagationTest.java">protectedServletCallingProtectedEJB</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Web has user principal set, but EJB not.">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/PublicEJBPropagationLogoutTest.java">publicServletCallingPublicEJBThenLogout</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="EJB did not clear authenticated identity after logout">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/PublicEJBPropagationTest.java">protectedServletCallingPublicEJB</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromSecureResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for secureResponse for protected resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for secureResponse for protected resource. (note: this is not required by the spec)">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromValidateRequest</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromSecureResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for secureResponse for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for secureResponse for public resource. (note: this is not required by the spec)">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromValidateRequest</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromSecureResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from EJB bean for secureResponse for protected resource. (note: spec is silent on this, but it should work)">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from EJB bean for secureResponse for protected resource. (note: spec is silent on this, but it should work)">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromValidateRequest</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from EJB bean for validateRequest for protected resource. (note: spec is silent on this, but it should work)">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromSecureResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from EJB bean for secureResponse for public resource.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from EJB bean for secureResponse for public resource.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromValidateRequest</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from EJB bean for validateRequest for public resource.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation">jacc-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation/src/test/java/org/javaee7/jaspic/jaccpropagation/JACCPropagationProtectedTest.java">callingJACCWhenAuthenticated</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Did not have access to protected servlet from within that Servlet. Perhaps the roles did not propogate from JASPIC to JACC and the server didn't use JACC to grant access to invoking said Servlet?">Failure</div></td> <td bgcolor="LightCoral"><div title="Did not have access to protected servlet from within that Servlet. Perhaps the roles did not propogate from JASPIC to JACC and the server didn't use JACC to grant access to invoking said Servlet?">Failure</div></td> <td bgcolor="LightCoral"><div title="Did not have access to protected servlet from within that Servlet. Perhaps the roles did not propogate from JASPIC to JACC and the server didn't use JACC to grant access to invoking said Servlet?">Failure</div></td> <td bgcolor="LightCoral"><div title="Did not have access to protected servlet from within that Servlet. Perhaps the roles did not propogate from JASPIC to JACC and the server didn't use JACC to grant access to invoking said Servlet?">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation">jacc-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation/src/test/java/org/javaee7/jaspic/jaccpropagation/JACCPropagationPublicTest.java">callingJACCWhenAuthenticated</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Did not have access to protected servlet from within public servlet. Perhaps the roles did not propogate from JASPIC to JACC?">Failure</div></td> <td bgcolor="LightCoral"><div title="Did not have access to protected servlet from within public servlet. Perhaps the roles did not propogate from JASPIC to JACC?">Failure</div></td> <td bgcolor="LightCoral"><div title="Did not have access to protected servlet from within public servlet. Perhaps the roles did not propogate from JASPIC to JACC?">Failure</div></td> <td bgcolor="LightCoral"><div title="Did not have access to protected servlet from within public servlet. Perhaps the roles did not propogate from JASPIC to JACC?">Failure</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation">jacc-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/jacc-propagation/src/test/java/org/javaee7/jaspic/jaccpropagation/JACCPropagationPublicTest.java">callingJACCWhenNotAuthenticated</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle">lifecycle</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle/src/test/java/org/javaee7/jaspic/lifecycle/AuthModuleMethodInvocationTest.java">testBasicSAMMethodsCalled</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="SAM method secureResponse not called, but should have been.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle">lifecycle</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle/src/test/java/org/javaee7/jaspic/lifecycle/AuthModuleMethodInvocationTest.java">testLogout</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionTest.java">testJoinSessionIsOptional</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionTest.java">testRemembersSession</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes">status-codes</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes/src/test/java/org/javaee7/jaspic/statuscodes/ProtectedStatusCodesTest.java">test404inResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response should have 404 not found as status code, but did not. expected:<404> but was:<500>">Failure</div></td> <td bgcolor="LightCoral"><div title="Response should have 404 not found as status code, but did not. expected:<404> but was:<500>">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes">status-codes</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes/src/test/java/org/javaee7/jaspic/statuscodes/PublicStatusCodesTest.java">test404inResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response should have 404 not found as status code, but did not. expected:<404> but was:<500>">Failure</div></td> <td bgcolor="LightCoral"><div title="Response should have 404 not found as status code, but did not. expected:<404> but was:<500>">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping">wrapping</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping/src/test/java/org/javaee7/jaspic/wrapping/WrappingTest.java">testResponseWrapping</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping">wrapping</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping/src/test/java/org/javaee7/jaspic/wrapping/WrappingTest.java">testRequestWrapping</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td></tr></table></div> <p>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 <b>finally</b> works without the need of modifying WildFly by <a href="http://arjan-tijms.omnifaces.org/2015/08/activating-jaspic-in-jboss-wildfly.html">putting a dummy fragment in its standalone.xml file</a>. 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! <p>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 <a href="https://issues.jboss.org/browse/WFLY-5739">doesn't work</a>. 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?". <p>The top performer as of now is <b>Payarra</b>, 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. <p>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. <p><i>Arjan Tijms</i> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com0tag:blogger.com,1999:blog-4498889353428710313.post-23689229854496469032015-11-12T16:10:00.000-08:002016-05-01T04:44:26.221-07:00The state of portable authentication for GlassFish, Payara, JBoss/WildFly, WebLogic and LibertyAlmost exactly 3 years ago I took an initial look at <a href="http://arjan-tijms.omnifaces.org/2012/11/implementing-container-authentication.html">custom container authentication in Java EE</a>. 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. <p>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 <a href="http://arjan-tijms.omnifaces.org/2013/04/whats-new-in-java-ee-7s-authentication.html#AppContextID">rectified this</a>. <p>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 <a href="http://arjan-tijms.omnifaces.org/2013/04/whats-new-in-java-ee-7s-authentication.html#LoginLogout">rectified these omissions</a> <a href="http://arjan-tijms.omnifaces.org/2013/04/whats-new-in-java-ee-7s-authentication.html#ForwardInclude">too</a>. <p>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. <p>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. <p>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. <p>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). <p>In response to this I created a series of tests, that were later donated to the <a href="https://github.com/javaee-samples/javaee7-samples/tree/master/jaspic">Java EE 7 samples project</a>. Subsequently I worked with all vendors and <a href="https://jaspic.zeef.com/arjan.tijms#block_63051_implementations-issue-tracking">asked them</a> 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. <p>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: <div style="font-size:75%;"><table border="1"><caption>Running the Java EE 7 samples JASPIC tests</caption><tr style="background-color:LightGray"><th>Module</th> <th>Test</th> <th>GlassFish 4.1.1</th> <th>Payara 4.1.1.154</th> <th><small>JBoss EAP 7 alpha1 <br/> WildFly 10rc4</small></th> <th>WebLogic 12.2.1</th> <th>Liberty <small>8.5.5.7 <br/>9 beta 2015.10</small></th></tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle">lifecycle</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle/src/test/java/org/javaee7/jaspic/lifecycle/AuthModuleMethodInvocationTest.java">testBasicSAMMethodsCalled</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle">lifecycle</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/lifecycle/src/test/java/org/javaee7/jaspic/lifecycle/AuthModuleMethodInvocationTest.java">testLogout</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationProtectedTest.java">testProtectedPageNotLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationProtectedTest.java">testProtectedPageLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Protected resource could be accessed, but the user appears to be the unauthenticated user. This should not be possible">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationPublicTest.java">testPublicPageLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="User should have been authenticated and given name "test", but does not appear to have this name">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationPublicTest.java">testPublicPageNotLoggedin</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="User should have been authenticated and given name "test", but does not appear to have this name">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedAccessIsStateless2</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication">basic-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/basic-authentication/src/test/java/org/javaee7/jaspic/basicauthentication/BasicAuthenticationStatelessTest.java">testProtectedThenPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFCDIForwardTest.java">testJSFwithCDIForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFCDIForwardTest.java">testJSFwithCDIForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFIncludeTest.java">testJSFIncludeViaPublicResource</a></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFForwardTest.java">testJSFForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFForwardTest.java">testJSFForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIForwardTest.java">testCDIForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIForwardTest.java">testCDIForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/CDIIncludeTest.java">testCDIIncludeViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from target Servlet after included one.">Failure</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi">dispatching-jsf-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching-jsf-cdi/src/test/java/org/javaee7/jaspictest/dispatching/JSFCDIIncludeTest.java">testJSFwithCDIIncludeViaPublicResource</a></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from JSF view that SAM included.">Failure</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicIncludeTest.java">testBasicIncludeViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from target Servlet after included one.">Failure</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicForwardTest.java">testBasicForwardViaProtectedResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching">dispatching</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/dispatching/src/test/java/org/javaee7/jaspic/dispatching/BasicForwardTest.java">testBasicForwardViaPublicResource</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalPublicTest.java">testPublicPageLoggedin</a></td> <td bgcolor="LightCoral"><div title="Username and roles are correct, but principal type is not the expected custom type.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Username is not the expected one 'test'">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Username is not the expected one 'test'">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedAccessIsStateless2</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalStatelessTest.java">testProtectedThenPublicAccessIsStateless</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal">custom-principal</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/custom-principal/src/test/java/org/javaee7/jaspictest/customprincipal/CustomPrincipalProtectedTest.java">testProtectedPageLoggedin</a></td> <td bgcolor="LightCoral"><div title="Authentication succeeded and username and roles are correct, but principal type is not the expected custom type.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Authentication but username is not the expected one 'test'">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromSecureResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for secureResponse for protected resource. (note: this is not required by the spec)">Failure</div></td><td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for secureResponse for protected resource. (note: this is not required by the spec)">Failure</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for cleanSubject for protected resource. (note: this is not required by the spec)">Failure</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanProtectedTest.java">protectedInvokeCDIFromValidateRequest</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for validateRequest for protected resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for validateRequest for protected resource. (note: this is not required by the spec)">Failure</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromSecureResponse</a></td> <td bgcolor="LightCoral"><div title="Response did not contain output from EJB bean for secureResponse for protected resource.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from EJB bean for secureResponse for protected resource.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanProtectedTest.java">protectedInvokeEJBFromValidateRequest</a></td> <td bgcolor="LightCoral"><div title="Response did not contain output from EJB bean for validateRequest for protected resource.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from EJB bean for validateRequest for protected resource.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromSecureResponse</a></td> <td bgcolor="LightCoral"><div title="Response did not contain output from EJB bean for secureResponse for public resource.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from EJB bean for secureResponse for public resource.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromValidateRequest</a></td> <td bgcolor="LightCoral"><div title="Response did not contain output from EJB bean for validateRequest for public resource.">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from EJB bean for validateRequest for public resource.">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeEJBBeanPublicTest.java">publicInvokeEJBFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromSecureResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for secureResponse for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for secureResponse for public resource. (note: this is not required by the spec)">Failure</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromValidateRequest</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for validateRequest for public resource. (note: this is not required by the spec)">Failure</div></td> <td bgcolor="LightCoral"><div title="Response did not contain output from CDI bean for validateRequest for public resource. (note: this is not required by the spec)">Failure</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi">invoke-ejb-cdi</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/invoke-ejb-cdi/src/test/java/org/javaee7/jaspictest/invoke/InvokeCDIBeanPublicTest.java">publicInvokeCDIFromCleanSubject</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionTest.java">testJoinSessionIsOptional</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Could not access protected page, but should be able to. Did the container not remember the authenticated identity via 'javax.servlet.http.registerSession'?">Failure</div></td> <td bgcolor="LightCoral"><div title="">Failure</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session">register-session</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionTest.java">testRemembersSession</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="Could not access protected page, but should be able to. Did the container not remember the authenticated identity via 'javax.servlet.http.registerSession'?">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes">status-codes</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes/src/test/java/org/javaee7/jaspic/statuscodes/PublicStatusCodesTest.java">test404inResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Response should have 404 not found as status code, but did not. expected:<404> but was: <500>">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes">status-codes</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/status-codes/src/test/java/org/javaee7/jaspic/statuscodes/ProtectedStatusCodesTest.java">test404inResponse</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div tooltip="Response should have 404 not found as status code, but did not. expected:<404> but was:<500>">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr> <tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/async-authentication">async-authentication</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/async-authentication/src/test/java/org/javaee7/jaspic/asyncauthentication/AsyncAuthenticationPublicTest.java">testBasicAsync</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/PublicEJBPropagationLogoutTest.java">publicServletCallingPublicEJBThenLogout</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="User should have been authenticated in the web layer and given name "test", but does not appear to have this name">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/ProtectedEJBPropagationTest.java">protectedServletCallingProtectedEJB</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="User should have been authenticated in the web layer and given name "test", but does not appear to have this name">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/ProtectedEJBPropagationTest.java">protectedServletCallingPublicEJB</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="User should have been authenticated in the web layer and given name "test", but does not appear to have this name">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation">ejb-propagation</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/ejb-propagation/src/test/java/org/javaee7/jaspic/ejbpropagation/PublicEJBPropagationTest.java">publicServletCallingProtectedEJB</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="LightCoral"><div title="User should have been authenticated in the web layer and given name "test", but does not appear to have this name">Failure</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping">wrapping</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping/src/test/java/org/javaee7/jaspic/wrapping/WrappingTest.java">testResponseWrapping</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr><tr> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping">wrapping</a></td> <td><a href="https://github.com/javaee-samples/javaee7-samples/blob/master/jaspic/wrapping/src/test/java/org/javaee7/jaspic/wrapping/WrappingTest.java">testRequestWrapping</a></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td> <td bgcolor="lightgreen"><div title="">Passed</div></td><tr></table></div> <p>&nbsp; <p>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. <i>request#getUserPrincipal()</i> still returns null and <i>request#isUserInRole()</i> returns false. This unfortunately means that for the moment until this bug is fixed JASPIC can not really be used on WebLogic at all. <p>Looking further at the results we see that the seemingly difficult to understand "<i>secureResponse</i>" 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. <p>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 <small>(<i>as a JSF EG member and Mojarra committer this is something I probably have to fix myself ;)</i>)</small> <p>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. <p>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 <a href="https://java.net/jira/browse/GLASSFISH-21447">is just a bug</a>. 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. <p>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. <i>org.example.MyPrincipal</i>, which then has to be returned from <i>request#getUserPrincipal()</i>. 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. <p>Setting a response status code from a SAM (like e.g. a 404 - NOT FOUND) is something that is supported by all Servers, except for JBoss EAP/WildFly. This is currently the only unique failure for WildFly. Sort of, since it actually <a href="https://github.com/undertow-io/undertow/commit/6e9663576fcaaa14f5a9cedf4ae1a144b20fd09e">has already been fixed</a>, but a build containing that fix has not yet been released. <p>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, <a href="http://arjan-tijms.omnifaces.org/2015/08/activating-jaspic-in-jboss-wildfly.html">JBoss EAP/WildFly indeeds needs such activation</a>. 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. <p>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 <a href="http://trajano.net/2015/08/websphere-liberty-noopuserregistry-add-on">NOOP user registry is installed and configured.</a> <h3>Conclusion</h3> <p>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. <p>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. <p>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. <p>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. <p><i>Arjan Tijms</i> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com1tag:blogger.com,1999:blog-4498889353428710313.post-52712210932201391772015-10-04T16:24:00.000-07:002015-10-05T10:14:44.631-07:00How Servlet containers all implement identity stores differentlyIn Java EE security two artefacts play a major role, the <b>authentication mechanism</b> and the <b>identity store</b>. <p>The <b>authentication mechanism</b> 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 <a href="https://en.wikipedia.org/wiki/Model–view–controller">MVC</a> architecture. <p>Java EE has standardised 4 authentication mechanisms for a Servlet container, as well as a <a href="https://jaspic.zeef.com/arjan.tijms">JASPIC</a> 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. <p>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. <small><i>(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)</i></small> <p>The following table enumerates the standard options: <ol><li>Basic</li><li>Digest <small><i>(encouraged to be supported, not required)</i></small></li><li>Client-cert</li><li>Form</li><li>Custom/<a href="https://jaspic.zeef.com/arjan.tijms">JASPIC</a> <small><i>(encouraged for standalone/web profile Servlet containers, required for full profile Servlet containers)</i></small> </li></ol> <p>The <b>identity store</b> 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. <p>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 <a href="https://blogs.oracle.com/nasradu8/entry/loginmodule_bridge_profile_jaspic_in">bridge profile for JAAS LoginModules</a>, 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 <a href="http://arjan-tijms.omnifaces.org/2014/02/jaas-in-java-ee-is-not-universal.html">essential elements of them are not standardised</a>. 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. <p>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: <ul> <li> In-memory (properties file/xml file based) </li> <li> Database (JDBC/DataSource based) </li> <li> LDAP </li></ul> <p>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: <div style="font-size:75%;"><ol><li> authenticator <li> authentication provider <li> authentication repository <li> authentication realm <li> authentication store <li> identity manager <li> identity provider <li> identity store <li> login module <li> login service <li> realm <li> relying party <li> security policy domain <li> security domain <li> service provider <li> user registry </ol></div> <p>Following a vote in the EG for the new Java EE security JSR, <a href="https://java.net/jira/browse/JAVAEE_SECURITY_SPEC-1">it was decided</a> to use the term "identity store" going forward. This is therefor also the term used in this article. <p>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. <p>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. <ol><li> <a href="#tomcat">Tomcat</a> </li><li> <a href="#jetty">Jetty</a> </li><li> <a href="#undertow">Undertow</a> </li><li> <a href="#jboss">JBoss EAP/WildFly</a></li><li> <a href="#resin">Resin</a></li><li> <a href="#glassfish">GlassFish</a></li><li> <a href="#liberty">Liberty</a></li><li> <a href="#WebLogic">WebLogic</a></li> </ol> <p>&nbsp; <a name="tomcat"></a><h3>Tomcat</h3><p> Tomcat calls its identity store "<a href="https://tomcat.apache.org/tomcat-8.0-doc/realm-howto.html">Realm</a>". It's represented by the interface shown below: <pre class="brush: java;"><br />public interface Realm {<br /> <br /> Principal authenticate(String username);<br /> Principal authenticate(String username, String credentials);<br /> Principal authenticate(String username, String digest, String nonce, String nc, String cnonce, String qop, String realm, String md5a2);<br /> Principal authenticate(GSSContext gssContext, boolean storeCreds);<br /> Principal authenticate(X509Certificate certs[]);<br /><br /> void backgroundProcess();<br /> SecurityConstraint [] findSecurityConstraints(Request request, Context context);<br /> boolean hasResourcePermission(Request request, Response response, SecurityConstraint[] constraint, Context context) throws IOException;<br /> boolean hasRole(Wrapper wrapper, Principal principal, String role);<br /> boolean hasUserDataPermission(Request request, Response response, SecurityConstraint[] constraint) throws IOException;<br /><br /> void addPropertyChangeListener(PropertyChangeListener listener);<br /> void removePropertyChangeListener(PropertyChangeListener listener);<br /><br /> Container getContainer();<br /> void setContainer(Container container);<br /> CredentialHandler getCredentialHandler();<br /> void setCredentialHandler(CredentialHandler credentialHandler);<br />}<br /></pre> <p>According to the <a href="https://tomcat.apache.org/tomcat-8.0-doc/realm-howto.html">documentation</a>, "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." <p>Tomcat's bare identity store interface is rather big as can be seen. In practice though implementations inherit from <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/tomcat-catalina/8.0.22/org/apache/catalina/realm/RealmBase.java#RealmBase">RealmBase</a>, 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". <p>The only methods that most of Tomcat's identity stores implement are <i>authenticate(String username, String credentials)</i> for the actual authentication, <i>String getName()</i> to return the identity store's name (this would perhaps have been an annotation if this was designed today), and <i>startInternal()</i> to do initialisation (would likely be done via an @PostConstruct annotation today). <p><h4>Example of usage</h4> <p>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 <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/tomcat-catalina/8.0.20/org/apache/catalina/authenticator/FormAuthenticator.java#FormAuthenticator.authenticate%28org.apache.catalina.connector.Request%2Cjavax.servlet.http.HttpServletResponse%29">FORM authentication mechanism</a> in Tomcat. <pre class="brush: java;"><br />// Obtain reference to identity store<br />Realm realm = context.getRealm();<br /><br />if (characterEncoding != null) {<br /> request.setCharacterEncoding(characterEncoding);<br />}<br />String username = request.getParameter(FORM_USERNAME);<br />String password = request.getParameter(FORM_PASSWORD);<br /><br />// Delegating of authentication mechanism to identity store<br />principal = realm.authenticate(username, password);<br /><br />if (principal == null) {<br /> forwardToErrorPage(request, response, config);<br /> return false;<br />}<br /><br />if (session == null) {<br /> session = request.getSessionInternal(false);<br />}<br /><br />// Save the authenticated Principal in our session<br />session.setNote(FORM_PRINCIPAL_NOTE, principal);<br /></pre> <p>What sets Tomcat aside from most other systems is that the <i>authenticate()</i> 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 <i>RealmBase</i> is used. <p>&nbsp; <a name="jetty"></a><h3>Jetty</h3><p> Jetty calls its identity store LoginService. It's represented by the interface shown below: <pre class="brush: java;"><br />public interface LoginService {<br /> String getName();<br /> UserIdentity login(String username, Object credentials, ServletRequest request);<br /> boolean validate(UserIdentity user);<br /><br /> IdentityService getIdentityService();<br /> void setIdentityService(IdentityService service);<br /> <br /> void logout(UserIdentity user);<br />}<br /></pre> <p>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". <p>There are a few things to remark here. The <i>getName()</i> method names the identity store. This would likely be done via an annotation had this interface been designed today. <p>The essential method of the Jetty identity store is <i>login()</i>. It's username/credentials based, where the credentials are an opaque Object. The <i>ServletRequest</i> is not often used, but a JAAS bridge uses it to provide a <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.eclipse.jetty/jetty-jaas/9.3.0.RC1/org/eclipse/jetty/jaas/callback/RequestParameterCallback.java#RequestParameterCallback">RequestParameterCallback</a> to Jetty specific JAAS LoginModules. <p><i>validate()</i> is essentially a kind of shortcut method for <i>login() != null</i>, albeit without using the credentials. <p>A distinguishing aspect of Jetty is that its identity stores get injected with an <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.eclipse.jetty/jetty-security/9.3.0.RC1/org/eclipse/jetty/security/IdentityService.java#IdentityService">IdentityService</a>, 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 <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.eclipse.jetty/jetty-security/9.3.0.RC1/org/eclipse/jetty/security/DefaultIdentityService.java#DefaultIdentityService">the only implementation</a> of this service just returns <i>new DefaultUserIdentity(subject, userPrincipal, roles)</i>, where DefaultUserIdentity is mostly just a simple POJO that encapsulates those three data items. <p>Another remarkable method is <i>logout()</i>. 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, <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.eclipse.jetty/jetty-jaas/9.3.0.RC1/org/eclipse/jetty/jaas/JAASLoginService.java#285">on which the logout() method is called</a> at this point. <p> <p><h4>Example of usage</h4> <p>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 <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.eclipse.jetty/jetty-security/9.3.0.RC1/org/eclipse/jetty/security/authentication/FormAuthenticator.java#FormAuthenticator">FORM authentication mechanism</a> in Jetty. <pre class="brush: java;"><br />if (isJSecurityCheck(uri)) {<br /> String username = request.getParameter(__J_USERNAME);<br /> String password = request.getParameter(__J_PASSWORD);<br /><br /> // Delegating of authentication mechanism to identity store<br /> UserIdentity user = _loginService.login(username, password, request);<br /> if (user != null) {<br /> renewSession(request, (request instanceof Request? ((Request)request).getResponse() : null));<br /> <br /> HttpSession session = request.getSession(true);<br /> session.setAttribute(__J_AUTHENTICATED, new SessionAuthentication(getAuthMethod(), user, password));<br /><br /> // ...<br /><br /> base_response.sendRedirect(redirectCode, response.encodeRedirectURL(nuri));<br /> return form_auth;<br /> }<br /> // ...<br />}<br /></pre> <p>In Jetty a call to the identity store's <i>login()</i> 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 <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.eclipse.jetty/jetty-security/9.3.0.RC1/org/eclipse/jetty/security/MappedLoginService.java#MappedLoginService">convenience base class</a> that identity store implementations can use, but this is not required. <p>If the base class is used, two abstract methods have to be implemented; <i>UserIdentity loadUser(String username)</i> and <i>void loadUsers()</i>, where typically only the former really does something. When this base class is indeed used, the above call to <i>login()</i> 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 <i>loadUser()</i> class. <pre class="brush: java;"><br />public UserIdentity login(String username, Object credentials, ServletRequest request) {<br /> <br /> UserIdentity user = _users.get(username);<br /><br /> if (user == null)<br /> user = loadUser(username);<br /><br /> if (user != null) {<br /> UserPrincipal principal = (UserPrincipal) user.getUserPrincipal();<br /> if (principal.authenticate(credentials))<br /> return user;<br /> }<br /><br /> return null;<br />}<br /></pre> <p>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: <pre class="brush: java;"><br />public boolean authenticate(Object credentials) {<br /> return credential != null && credential.check(credentials);<br />}<br /></pre> <p>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: <pre class="brush: java;"><br />public boolean check(Object credentials) {<br /> if (this == credentials) <br /> return true;<br /> if (credentials instanceof Password)<br /> return credentials.equals(_pw);<br /> if (credentials instanceof String)<br /> return credentials.equals(_pw);<br /> if (credentials instanceof char[]) <br /> return Arrays.equals(_pw.toCharArray(), (char[]) credentials);<br /> if (credentials instanceof Credential) <br /> return ((Credential) credentials).check(_pw);<br /> return false;<br />}<br /></pre> <p>&nbsp; <a name="undertow"></a><h3>Undertow</h3><p>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. <p>The native identity store interface of Undertow is the <a href="https://developer.jboss.org/wiki/Undertow-IdentityManager">IdentityManager</a>, which is shown below: <pre class="brush: java;"><br />public interface IdentityManager {<br /> Account verify(Credential credential);<br /> Account verify(String id, Credential credential);<br /> Account verify(Account account);<br />}<br /></pre> Peculiar enough there are no direct implementations for actual identity stores shipped with Undertow. <p><h4>Example of usage</h4> <p>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 <a href="http://grepcode.com/file/repo1.maven.org/maven2/io.undertow/undertow-core/1.2.7.Final/io/undertow/security/impl/FormAuthenticationMechanism.java#FormAuthenticationMechanism.runFormAuth%28io.undertow.server.HttpServerExchange%2Cio.undertow.security.api.SecurityContext%29">FORM authentication mechanism</a> in Undertow. <pre class="brush: java;"><br />FormData data = parser.parseBlocking();<br />FormData.FormValue jUsername = data.getFirst("j_username");<br />FormData.FormValue jPassword = data.getFirst("j_password");<br />if (jUsername == null || jPassword == null) {<br /> return NOT_AUTHENTICATED;<br />}<br /><br />String userName = jUsername.getValue();<br />String password = jPassword.getValue();<br />AuthenticationMechanismOutcome outcome = null;<br />PasswordCredential credential = new PasswordCredential(password.toCharArray());<br /><br />// Obtain reference to identity store<br />IdentityManager identityManager = securityContext.getIdentityManager();<br /><br />// Delegating of authentication mechanism to identity store<br />Account account = identityManager.verify(userName, credential);<br /><br />if (account != null) {<br /> securityContext.authenticationComplete(account, name, true);<br /> outcome = AUTHENTICATED;<br />} else {<br /> securityContext.authenticationFailed(MESSAGES.authenticationFailed(userName), name);<br />}<br /><br />if (outcome == AUTHENTICATED) {<br /> handleRedirectBack(exchange);<br /> exchange.endExchange();<br />}<br /><br />return outcome != null ? outcome : NOT_AUTHENTICATED;<br /></pre> <p>&nbsp; <a name="jboss"></a><h3>JBoss EAP/WildFly</h3><p> JBoss identity stores are based on the JAAS LoginModule, which is shown below: <pre class="brush: java;"><br />public interface LoginModule {<br /> void initialize(Subject subject, CallbackHandler callbackHandler, Map&lt;String,?> sharedState, Map&lt;String,?> options);<br /> boolean login() throws LoginException;<br /> boolean commit() throws LoginException;<br /> boolean abort() throws LoginException;<br /> boolean logout() throws LoginException;<br />}<br /></pre> As with most application servers, the JAAS LoginModule interface is used in a highly application server specific way. <p>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. <p>For the username/password credential the base class to inherit from is <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.picketbox/picketbox/4.9.2.Final/org/jboss/security/auth/spi/UsernamePasswordLoginModule.java#UsernamePasswordLoginModule">UsernamePasswordLoginModule</a>. As per the JavaDoc of this class, there are two methods that need to be implemented: <i>getUsersPassword()</i> and <i>getRoleSets()</i>. <p><i>getUsersPassword()</i> 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 <i>getRoleSets()</i> 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 <i>getUsername()</i>. <p>The "real" contract as *hypothetical* interface could be thought of to look as follows: <pre class="brush: java;"><br />public interface JBossIdentityStore {<br /> String getUsersPassword(String username);<br /> Group[] getRoleSets(String username) throws LoginException;<br />}<br /></pre> <p><h4>Example of usage</h4> <p>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. <p>For usage in JBoss there's a <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.wildfly/wildfly-undertow/9.0.0.CR1/org/wildfly/extension/undertow/security/JAASIdentityManagerImpl.java#JAASIdentityManagerImpl">bridge implementation</a> of the IdentityManager to the JBoss specific JAAS LoginModule available. <p>The "identityManager.verify(userName, credential)" call shown above ends up at <i>JAASIdentityManagerImpl#verify</i>. This first wraps the username, but extracts the password from <i>PasswordCredential</i>. Abbreviated it looks as follows: <pre class="brush: java;"><br />public Account verify(String id, Credential credential) {<br /> if (credential instanceof DigestCredential) {<br /> // ..<br /> } else if(credential instanceof PasswordCredential) {<br /> return verifyCredential(<br /> new AccountImpl(id), <br /> copyOf(((PasswordCredential) credential).getPassword())<br /><br /> );<br /> } <br /> return verifyCredential(new AccountImpl(id), credential); <br />}<br /></pre> 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 <i>isValid()</i> 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. <p>Abbreviated again this looks as follows: <pre class="brush: java;"><br />private Account verifyCredential(AccountImpl account, Object credential) <br /> Subject subject = new Subject(); <br /> boolean isValid = securityDomainContext<br /> .getAuthenticationManager()<br /> .isValid(account.getOriginalPrincipal(), credential, subject);<br /><br /> if (isValid) {<br /> <br /> // Stores details in TLS<br /> getSecurityContext()<br /> .getUtil()<br /> .createSubjectInfo(account.getOriginalPrincipal(), credential, subject);<br /><br /> return new AccountImpl(<br /> getPrincipal(subject), getRoles(subject),<br /> credential, account.getOriginalPrincipal()<br /> );<br /> }<br /><br /> return null;<br />}<br /></pre> The next method being called is <i>isValid()</i> on a type called AuthenticationManager. Via two intermediate methods this ends up calling <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.picketbox/picketbox/4.9.2.Final/org/jboss/security/plugins/auth/JaasSecurityManagerBase.java#JaasSecurityManagerBase.proceedWithJaasLogin%28java.security.Principal%2Cjava.lang.Object%2Cjavax.security.auth.Subject%29">proceedWithJaasLogin</a>. <p>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: <pre class="brush: java;"><br />private boolean proceedWithJaasLogin(Principal principal, Object credential, Subject theSubject) {<br /> try {<br /> copySubject(defaultLogin(principal, credential).getSubject(), theSubject);<br /> return true;<br /> } catch (LoginException e) {<br /> return false; <br /> }<br />}<br /></pre> <p>The <i>defaultLogin()</i> method finally just calls plain Java SE JAAS code, although just before doing that it uses reflection to call a <i>setSecurityInfo()</i> 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 <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.picketbox/picketbox/4.9.2.Final/org/jboss/security/auth/callback/JBossCallbackHandler.java#JBossCallbackHandler">JBossCallbackHandler</a>. <p>Brought back to its essence the method looks like this: <pre class="brush: java;"><br />private LoginContext defaultLogin(Principal principal, Object credential) throws LoginException {<br /> <br /> CallbackHandler theHandler = (CallbackHandler) handler.getClass().newInstance();<br /> setSecurityInfo.invoke(theHandler, new Object[] {principal, credential});<br /> <br /> LoginContext lc = new LoginContext(securityDomain, subject, handler);<br /> lc.login();<br /><br /> return lc;<br />}<br /></pre> <p>Via some reflective magic the JAAS code shown here will locate, instantiate and at long last will call our custom LoginModule's <i>initialize()</i>, <i>login()</i> and <i>commit()</i> methods, which on their turn will call the two methods that we needed to implement in our subclass. <p>&nbsp; <a name="resin"></a><h3>Resin</h3><p> Resin calls its identity store "Authenticator". It's represented by a single interface shown below: <pre class="brush: java;"><br />public interface Authenticator {<br /> String getAlgorithm(Principal uid);<br /> Principal authenticate(Principal user, Credentials credentials, Object details);<br /> boolean isUserInRole(Principal user, String role);<br /> void logout(Principal user);<br />}<br /></pre> There are a few things to remark here. The <i>logout()</i> 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 <i>AbstractAuthenticator</i> that does nothing there. <p><i>isUserInRole()</i> 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 <a href="https://github.com/mdaniel/svn-caucho-com-resin/blob/master/modules/resin/src/com/caucho/server/http/AbstractCauchoRequest.java#L984">how it's used</a> 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 <a href="https://github.com/mdaniel/svn-caucho-com-resin/blob/master/modules/resin/src/com/caucho/security/DatabaseAuthenticator.java#L610">opt-in to actually use this</a>. <p><h4>Example of usage</h4> <p>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 <a href="https://github.com/mdaniel/svn-caucho-com-resin/blob/master/modules/resin/src/com/caucho/security/FormLogin.java#L216">FORM authentication mechanism</a> in Resin. <pre class="brush: java;"><br />// Obtain reference to identity store<br />Authenticator auth = getAuthenticator();<br /><br />// ..<br /><br />String userName = request.getParameter("j_username");<br />String passwordString = request.getParameter("j_password");<br /><br />if (userName == null || passwordString == null)<br /> return null;<br /><br />char[] password = passwordString.toCharArray();<br />BasicPrincipal basicUser = new BasicPrincipal(userName);<br />Credentials credentials = new PasswordCredentials(password);<br /><br />// Delegating of authentication mechanism to identity store<br />user = auth.authenticate(basicUser, credentials, request);<br /><br />return user;<br /></pre> <p>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. <p>That said, Resin does encourage (but not require) the usage of an abstract base class it provides: <a href="https://github.com/mdaniel/svn-caucho-com-resin/blob/master/modules/resin/src/com/caucho/server/security/AbstractAuthenticator.java">AbstractAuthenticator</a>. 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: <p><pre class="brush: java;"><br />public Principal authenticate(Principal user, Credentials credentials, Object details) {<br /> if (credentials instanceof PasswordCredentials)<br /> return authenticate(user, (PasswordCredentials) credentials, details);<br /> if (credentials instanceof HttpDigestCredentials)<br /> return authenticate(user, (HttpDigestCredentials) credentials, details);<br /> if (credentials instanceof DigestCredentials)<br /> return authenticate(user, (DigestCredentials) credentials, details);<br /> return null;<br />}<br /></pre> <p>Following the password trail, the next level will merely extract the password string: <pre class="brush: java;"><br />protected Principal authenticate(Principal principal, PasswordCredentials cred, Object details) {<br /> return authenticate(principal, cred.getPassword());<br />}<br /></pre> <p>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: <pre class="brush: java;"><br />protected Principal authenticate(Principal principal, char[] password) {<br /> PasswordUser user = getPasswordUser(principal);<br /><br /> if (user == null || user.isDisabled() || (!isMatch(principal, password, user.getPassword()) && !user.isAnonymous()))<br /> return null;<br /> <br /> return user.getPrincipal();<br />}<br /></pre> <p>The <i>getPasswordUser()</i> method goes through one more level of convenience, where it extracts the caller name that was wrapped by the Principal: <pre class="brush: java;"><br />protected PasswordUser getPasswordUser(Principal principal) {<br /> return getPasswordUser(principal.getName());<br />}<br /></pre> <p>This last call to <i>getPasswordUser(String)</i> is what typically ends up in our own custom identity store. <p>Finally, it's interesting to see what data PasswordUser contains. Abbreviated again this is shown below: <pre class="brush: java;"><br />public class PasswordUser {<br /> Principal principal;<br /> char[] password;<br /> <br /> boolean disabled;<br /> boolean anonymous;<br /> String[] roles;<br />}<br /></pre> <p>&nbsp; <a name="glassfish"></a><h3>Glassfish</h3><p>GlassFish identity stores are based on the JAAS LoginModule, which is shown below: <pre class="brush: java;"><br />public interface LoginModule {<br /> void initialize(Subject subject, CallbackHandler callbackHandler, Map&lt;String,?> sharedState, Map&lt;String,?> options);<br /> boolean login() throws LoginException;<br /> boolean commit() throws LoginException;<br /> boolean abort() throws LoginException;<br /> boolean logout() throws LoginException;<br />}<br /></pre> <p>Just as we saw with JBoss above, the <i>LoginModule</i> interface is again used in a very application server specific way. In practice, you don't just implement a LoginModule but inherit from <i>com.sun.enterprise.security.BasePasswordLoginModule</i> 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. <p>As per the JavaDoc of those classes, the only method that needs to be implemented is <i>authenticateUser()</i>. 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 <i>commitUserAuthentication()</i> 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. <p>The "real" contract as *hypothetical* interface looks as follows: <pre class="brush: java;"><br />public interface GlassFishIdentityStore {<br /> String[] authenticateUser(String username, char[] password) throws LoginException;<br />}<br /></pre> <p>Even though a LoginModule is specific for a type of identity store (e.g. File, JDBC/database, LDAP, etc), LoginModules in GlassFish are <a href="byorns.blogspot.com/2015/01/how-to-setup-custom-jaas-login-module.html">mandated to be paired with another construct called a Realm</a>. 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. <p>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. <p>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. <p>The following lists the public and protected methods of this Realm class. Note that the body is left out for the non-abstract methods. <div style="font-size:90%;"><pre class="brush: java;"><br />public abstract class Realm implements Comparable {<br /><br /> public static synchronized Realm getDefaultInstance();<br /> public static synchronized String getDefaultRealm();<br /> public static synchronized Enumeration getRealmNames();<br /> public static synchronized void getRealmStatsProvier();<br /> public static synchronized Realm getInstance(String);<br /> public static synchronized Realm instantiate(String, File);<br /> public static synchronized Realm instantiate(String, String, Properties);<br /> public static synchronized void setDefaultRealm(String);<br /> public static synchronized void unloadInstance(String);<br /> public static boolean isValidRealm(String);<br /> protected static synchronized void updateInstance(Realm, String);<br /><br /> public abstract void addUser(String, String, String[]);<br /> public abstract User getUser(String);<br /> public abstract void updateUser(String, String, String, String[]);<br /> public abstract void removeUser(String);<br /><br /> public abstract Enumeration getUserNames();<br /> public abstract Enumeration getGroupNames();<br /> public abstract Enumeration getGroupNames(String);<br /> <br /> public abstract void persist();<br /> public abstract void refresh();<br /><br /> public abstract AuthenticationHandler getAuthenticationHandler();<br /> public abstract boolean supportsUserManagement();<br /> public abstract String getAuthType(); <br /><br /> public int compareTo(Object);<br /> public String FinalgetName();<br /> public synchronized String getJAASContext();<br /> public synchronized String getProperty(String);<br /> public synchronized void setProperty(String, String);<br /><br /> protected void init(Properties);<br /> protected ArrayList&lt;String> getMappedGroupNames(String);<br /> protected String[] addAssignGroups(String[]);<br /> protected final void setName(String);<br /> protected synchronized Properties getProperties();<br />}<br /></pre></div> <p><h4>Example of usage</h4> <p>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: <div style="font-size:90%;"><pre class="brush: java;"><br />// Obtain reference to identity store<br />Realm realm = context.getRealm();<br /><br />String username = hreq.getParameter(FORM_USERNAME);<br />String pwd = hreq.getParameter(FORM_PASSWORD);<br />char[] password = ((pwd != null)? pwd.toCharArray() : null);<br /><br />// Delegating of authentication mechanism to identity store<br />principal = realm.authenticate(username, password);<br /> <br />if (principal == null) {<br /> forwardToErrorPage(request, response, config);<br /> return (false);<br />}<br /><br />if (session == null)<br /> session = getSession(request, true);<br /><br />session.setNote(FORM_PRINCIPAL_NOTE, principal);<br /></pre></div> <p>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: <div style="font-size:90%;"><pre class="brush: java;"><br />public Principal authenticate(String username, char[] password) {<br /> if (authenticate(username, password, null)) {<br /> return new WebPrincipal(username, password, SecurityContext.getCurrent());<br /> }<br /> return null;<br />}<br /></pre></div> Which on its turn calls the following abbreviated method that handles two supported types of credentials: <div style="font-size:90%;"><pre class="brush: java;"><br />protected boolean authenticate(String username, char[] password, X509Certificate[] certs) {<br /> try {<br /> if (certs != null) {<br /> // ... create subject<br /> LoginContextDriver.doX500Login(subject, moduleID);<br /> } else {<br /> LoginContextDriver.login(username, password, _realmName);<br /> }<br /> return true;<br /> } catch (Exception le) {}<br /> <br /> return false;<br />}<br /></pre></div> Again (strongly) abbreviated the login method called looks as follows: <div style="font-size:90%;"><pre class="brush: java;"><br />public static void login(String username, char[] password, String realmName){<br /> Subject subject = new Subject();<br /> subject.getPrivateCredentials().add(new PasswordCredential(username, password, realmName));<br /><br /> LoginContextDriver.login(subject, PasswordCredential.class);<br />}<br /></pre></div> <p>This new login method checks for several credential types, which abbreviated looks as follows: <div style="font-size:90%;"><pre class="brush: java;"><br />public static void login(Subject subject, Class cls) throws LoginException {<br /> if (cls.equals(PasswordCredential.class))<br /> doPasswordLogin(subject);<br /> else if (cls.equals(X509CertificateCredential.class))<br /> doCertificateLogin(subject);<br /> else if (cls.equals(AnonCredential.class)) {<br /> doAnonLogin();<br /> else if (cls.equals(GSSUPName.class)) {<br /> doGSSUPLogin(subject);<br /> else if (cls.equals(X500Name.class)) {<br /> doX500Login(subject, null);<br /> else<br /> throw new LoginException("Unknown credential type, cannot login.");<br />}<br /></pre></div> <p>As we're following the password trail, we're going to look at the doPasswordLogin() method here, which strongly abbreviated looks as follows: <div style="font-size:90%;"><pre class="brush: java;"><br />private static void doPasswordLogin(Subject subject) throws LoginException<br /> try {<br /> new LoginContext(<br /> Realm.getInstance(<br /> getPrivateCredentials(subject, PasswordCredential.class).getRealm()<br /> ).getJAASContext(), <br /> subject, <br /> dummyCallback<br /> ).login();<br /> } catch (Exception e) {<br /> throw new LoginException("Login failed: " + e.getMessage()).initCause(e);<br /> }<br />}<br /></pre></div> <p>We're now 5 levels deep, and we're about to see our custom login module being called. <p>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. <p>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: <div style="font-size:90%;"><pre class="brush: java;"><br />// methodName == "login" here<br /><br />// find the requested method in the LoginModule<br />for (mIndex = 0; mIndex < methods.length; mIndex++) {<br /> if (methods[mIndex].getName().equals(methodName))<br /> break;<br />}<br /><br />// set up the arguments to be passed to the LoginModule method<br />Object[] args = { };<br /><br />// invoke the LoginModule method<br />boolean status = ((Boolean) methods[mIndex].invoke(moduleStack[i].module, args)).booleanValue();<br /></pre></div> 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: <div style="font-size:90%;"><pre class="brush: java;"><br />final public boolean login() throws LoginException {<br /><br /> // Extract the username, password and realm name from the Subject<br /> extractCredentials();<br /> <br /> // Delegate the actual authentication to subclass (finally!)<br /> authenticateUser();<br /> <br /> return true;<br />}<br /></pre></div> <p>&nbsp; <a name="liberty"></a><h3>Liberty</h3><p> Liberty calls its identity stores "<a href="https://www-01.ibm.com/support/knowledgecenter/SS7JFU_8.5.5/com.ibm.websphere.javadoc.liberty.doc/com.ibm.websphere.appserver.api.securityClient_1.0-javadoc/com/ibm/websphere/security/UserRegistry.html">user registry</a>". It's shown below: <div style="font-size:90%;"><pre class="brush: java;"><br />public interface UserRegistry {<br /> void initialize(Properties props) throws CustomRegistryException, RemoteException;<br /><br /> String checkPassword(String userSecurityName, String password) throws PasswordCheckFailedException, CustomRegistryException, RemoteException;<br /> String mapCertificate(X509Certificate[] certs) throws CertificateMapNotSupportedException, CertificateMapFailedException, CustomRegistryException, RemoteException;<br /> String getRealm() throws CustomRegistryException, RemoteException;<br /><br /> Result getUsers(String pattern, int limit) throws CustomRegistryException, RemoteException;<br /> String getUserDisplayName(String userSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException;<br /> String getUniqueUserId(String userSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException;<br /> String getUserSecurityName(String uniqueUserId) throws EntryNotFoundException, CustomRegistryException, RemoteException;<br /> boolean isValidUser(String userSecurityName) throws CustomRegistryException, RemoteException;<br /><br /> Result getGroups(String pattern, int limit) throws CustomRegistryException, RemoteException;<br /> String getGroupDisplayName(String groupSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException;<br /> String getUniqueGroupId(String groupSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException;<br /> List<String> getUniqueGroupIds(String uniqueUserId) throws EntryNotFoundException, CustomRegistryException, RemoteException;<br /> String getGroupSecurityName(String uniqueGroupId) throws EntryNotFoundException, CustomRegistryException, RemoteException;<br /> boolean isValidGroup(String groupSecurityName) throws CustomRegistryException, RemoteException;<br /><br /> List<String> getGroupsForUser(String groupSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException;<br /> WSCredential createCredential(String userSecurityName) throws NotImplementedException, EntryNotFoundException, CustomRegistryException, RemoteException; <br />}<br /></pre></div> <p>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. <p>As can be seen though it has methods to list all users and groups that the identity store manages (<i>getUsers()</i>, <i>getGroups()</i>) 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 <a href="https://www-01.ibm.com/support/knowledgecenter/SS7JFU_8.5.5/com.ibm.websphere.javadoc.liberty.doc/com.ibm.websphere.appserver.api.securityClient_1.0-javadoc/com/ibm/websphere/security/UserRegistry.html">published JavaDoc</a> 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. <p><i>createCredential()</i> stands out as the JavaDoc mentions it's never been called for at least the 8.5.5 release of Liberty. <p>The main method that does the actual authentication is <i>checkPassword()</i>. 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, <i>mapCertificate()</i>, which seemingly has to be called first, and then the resulting username passed into <i>checkPassword()</i> again. <p><h4>Example of usage</h4> <p>Since Liberty is closed source we can't actually see how the server uses its identity store. Some implementation examples are given by <a href="https://developer.ibm.com/wasdev/docs/creating-a-custom-user-registry-as-a-liberty-user-feature">IBM</a> and <a href="http://arjan-tijms.omnifaces.org/2015/04/testing-jaspic-11-on-ibm-liberty-ee-7.html">myself</a>. <p>&nbsp; <a name="weblogic"></a><h3>WebLogic</h3><p> 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 <a href="http://docs.oracle.com/cd/E24329_01/web.1211/e24484/realm_chap.htm#SCOVR193">many more providers</a>. <p>One of the entry points seems to be an "<a href="http://docs.oracle.com/middleware/1213/wls/WLAPI/weblogic/security/spi/AuthenticationProviderV2.html">Authentication Provider V2</a>", which is given below: <pre class="brush: java;"><br />public interface AuthenticationProviderV2 extends SecurityProvider {<br /><br /> AppConfigurationEntry getAssertionModuleConfiguration(); <br /> IdentityAsserterV2 getIdentityAsserter();<br /> AppConfigurationEntry getLoginModuleConfiguration(); <br /> PrincipalValidator getPrincipalValidator();<br />}<br /></pre> <p>Here it looks like the <i>getLoginModuleConfiguration()</i> has to return an <i>AppConfigurationEntry</i> that holds the fully qualified class name of a JAAS LoginModule, which is given below: <pre class="brush: java;"><br />public interface LoginModule {<br /> void initialize(Subject subject, CallbackHandler callbackHandler, Map&lt;String,?> sharedState, Map&lt;String,?> options);<br /> boolean login() throws LoginException;<br /> boolean commit() throws LoginException;<br /> boolean abort() throws LoginException;<br /> boolean logout() throws LoginException;<br />}<br /></pre> <a href="http://weblogic-wonders.com/weblogic/2014/01/14/simple-sample-custom-database-authenticator-oracle-weblogic-server-11g">It</a> <a href="http://danielveselka.blogspot.com/2012/04/mock-weblogic-login-module-identity.html">seems</a> <a href="http://docs.oracle.com/cd/E13222_01/wls/docs92/dvspisec/atn.html">WebLogic's usage of the LoginModule</a> 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 <a href="http://arjan-tijms.omnifaces.org/2014/02/jaas-in-java-ee-is-not-universal.html">these are not standardized</a>. <p><h4>Example of usage</h4> <p>Since WebLogic is closed source it's not possible to see how it actually uses the Authentication Provider V2 and its associated Login Module. <p>&nbsp; <h3> Conclusion </h3> <p>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. <p>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. <p>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. <p>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. <p>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 <i>{credentials in, caller data out}</i> function. <p>It's exactly this <a href="https://java.net/jira/browse/JAVAEE_SECURITY_SPEC-18">bare minimum of functionality</a> 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 <a href="https://java.net/projects/javaee-security-spec/lists/jsr375-experts/archive/2015-10/message/1">currently looking at</a> in the security EG. <p><i>Arjan Tijms</i>Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com0tag:blogger.com,1999:blog-4498889353428710313.post-76731544709498199342015-08-21T06:22:00.000-07:002015-12-23T07:10:24.312-08:00Activating JASPIC in JBoss WildFlyJBoss WildFly has a rather good implementation of <a href="https://jaspic.zeef.com/arjan.tijms">JASPIC</a>, the Java EE standard API to build authentication modules. <p>Unfortunately there's one big hurdle for using <a href="https://jaspic.zeef.com/arjan.tijms">JASPIC</a> 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 <i>standalone.xml</i> that resides with the installed server: <pre class="brush: xml;"><br />&lt;security-domain name="jaspitest" cache-type="default"&gt;<br /> &lt;authentication-jaspi&gt;<br /> &lt;login-module-stack name="dummy"&gt;<br /> &lt;login-module code="Dummy" flag="optional"/&gt;<br /> &lt;/login-module-stack&gt;<br /> &lt;auth-module code="Dummy"/&gt;<br /> &lt;/authentication-jaspi&gt;<br />&lt;/security-domain&gt;<br /></pre> <p><b>UPDATE Dec 23, 2015: Since WildFly 10rc5 the "jaspitest" domain is included by default in standalone.xml and no longer has to be added manually. For JBoss EAP 7 beta1 and earlier this is still needed as it just predates the moment this domain was added. </b> <p>Subsequently in the application a file called <i>WEB-INF/jboss-web.xml</i> needs to be created that references this (dummy) domain: <pre class="brush: xml;"><br />&lt;?xml version="1.0"?><br />&lt;jboss-web><br /> &lt;security-domain>jaspitest&lt;/security-domain><br />&lt;/jboss-web><br /></pre> <p><b>UPDATE Dec 23, 2015: For WildFly 10rc5 and later the below is not longer relevant. Only the jboss-web.xml file as shown above has to be added to activate JASPIC</b> <p>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 <a href="https://github.com/javaee-samples/javaee7-samples/issues/243">forgotten</a> 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. <p>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. <p>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 <a href="https://github.com/omnifaces/omnisecurity-jaspic-undertow">OmniSecurity JASPIC Undertow</a> project comes in. With this project JASPIC can be activated by putting the following in the <i>pom.xml</i> of a Maven project: <pre class="brush: xml;"><br />&lt;dependency><br /> &lt;groupId>org.omnifaces&lt;/groupId><br /> &lt;artifactId>omnifaces-security-jaspic-undertow&lt;/artifactId><br /> &lt;version>1.0&lt;/version><br />&lt;/dependency><br /></pre> <p>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 <i>META-INF/jboss-deployment-structure.xml</i> file with the following content: <pre class="brush: xml;"><br />&lt;?xml version='1.0' encoding='UTF-8'?><br />&lt;jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2"><br /> &lt;deployment><br /> &lt;dependencies><br /> &lt;module name="org.wildfly.extension.undertow" services="export" export="true" /><br /> &lt;/dependencies><br /> &lt;/deployment><br />&lt;/jboss-deployment-structure><br /></pre> <p>So how does the extension exactly work? <p>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 <a href="https://jaspic.zeef.com/arjan.tijms">JASPIC</a>. This is basically the same code Undertow would execute if the dummy domain is put in <i>standalone.xml</i>. <p>For completeness, the reflective part to retrieve the domain is: <pre class="brush: java;"><br />String securityDomain = "other";<br /><br />IdentityManager identityManager = deploymentInfo.getIdentityManager();<br />if (identityManager instanceof JAASIdentityManagerImpl) {<br /> try {<br /> Field securityDomainContextField = JAASIdentityManagerImpl.class.getDeclaredField("securityDomainContext");<br /> securityDomainContextField.setAccessible(true);<br /> SecurityDomainContext securityDomainContext = (SecurityDomainContext) securityDomainContextField.get(identityManager);<br /><br /> securityDomain = securityDomainContext.getAuthenticationManager().getSecurityDomain();<br /><br /> } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {<br /> logger.log(Level.SEVERE, "Can't obtain name of security domain, using 'other' now", e);<br /> }<br />}<br /></pre> <p>The part that uses Undertow APIs to activate JASPIC is: <pre class="brush: java;"><br />ApplicationPolicy applicationPolicy = new ApplicationPolicy(securityDomain);<br />JASPIAuthenticationInfo authenticationInfo = new JASPIAuthenticationInfo(securityDomain);<br />applicationPolicy.setAuthenticationInfo(authenticationInfo);<br />SecurityConfiguration.addApplicationPolicy(applicationPolicy);<br /><br />deploymentInfo.setJaspiAuthenticationMechanism(new JASPIAuthenticationMechanism(securityDomain, null));<br />deploymentInfo.setSecurityContextFactory(new JASPICSecurityContextFactory(securityDomain));<br /></pre> <small>The <a href="https://github.com/omnifaces/omnisecurity-jaspic-undertow/blob/master/src/main/java/org/omnifaces/security/JaspicActivator.java">full source</a> can be found on GitHub.</small> <p><h3>Conclusion</h3> <p>For JBoss WildFly it's needed to activate <a href="https://jaspic.zeef.com/arjan.tijms">JASPIC</a>. There are two hacks available to do this. One requires a modification to <i>standalone.xml</i> and a <i>jboss-web.xml</i>, while the other requires a jar on the classpath of the application and a <i>jboss-deployment-structure.xml file</i>. <p>It would be best if such activation was not required at all. Hopefully this will indeed be the case in a future JBoss. <p><i>Arjan Tijms</i> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com4tag:blogger.com,1999:blog-4498889353428710313.post-18675863568682924292015-07-17T15:38:00.000-07:002015-07-17T15:47:11.163-07:00JSF 2.3 new feature: registrable DataModelsIterating components in JSF such as <i>h:dataTable</i> and <i>ui:repeat</i> have the <i>DataModel</i> class as their native input type. Other datatypes such as <i>List</i> are supported, but these are handled by build-in wrappers; e.g. an application provided <i>List</i> is wrapped into a <a href="http://docs.oracle.com/javaee/7/api/javax/faces/model/ListDataModel.html">ListDataModel</a>. <p>While JSF has steadily expanded the number of build-in wrappers and JSF 2.3 has provided new ones for <i><a href="http://jdevelopment.nl/jsf-23/#1364">Map</a></i> and <i><a href="http://jdevelopment.nl/jsf-23/#1103">Iterable</a></i>, a <a href="https://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1078">long standing request</a> is for users (or libraries) to be able to register their own wrappers. <p>JSF 2.3 will now (finally) let users do this. The way this is done is by creating a wrapper <i>DataModel</i> 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 <i>@FacesDataModel</i> annotation. A “forClass” attribute has to be specified on this annotation that designates the type this wrapper is able to handle. <p>The following gives an abbreviated example of this: <pre class="brush: java;"><br />@FacesDataModel(forClass = MyCollection.class)<br />public class MyCollectionModel&lt;E> extends DataModel&lt;E> {<br /> <br /> @Override<br /> public E getRowData() {<br /> // access MyCollection here<br /> }<br /><br /> @Override<br /> public void setWrappedData(Object myCollection) {<br /> // likely just store myCollection<br /> }<br /><br /> // Other methods omitted for brevity<br />}<br /></pre> <p>Note that there are two types involved here. The “forClass” attribute is the collection or container type that the <i>DataModel</i> wraps, while the generic parameter <i>E</i> concerns the data this collection contains. E.g. Suppose we have a <i>MyCollection&lt;User&gt;</i>, then “forClass” would correspond to <i>MyCollection</i>, and <i>E</i> would correspond to <i>User</i>. If set/getWrappedData was generic the “forClass” attribute may not have been needed, as generic parameters can be read from class definitions, but alas. <p>With a class definition as given above present, a backing bean can now return a <i>MyCollection</i> as in the following example: <pre class="brush: java;"><br />@Named<br />public class MyBacking {<br /> public MyCollection&lt;User> getUsers() {<br /> // return myCollection<br /> }<br />}<br /></pre> h:dataTable will be able to work with this directly, as shown in the example below: <pre class="brush: xml;"><br />&lt;h:dataTable value="#{myBacking.users}" var="user"><br /> &lt;h:column>#{user.name}&lt;/h:column><br />&lt;/h:dataTable><br /></pre> <p>There are a few things noteworthy here. <p>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). <p>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. <p>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 <i>List</i> and one was provided via <i>@FacesDataModel</i>. Now also suppose the actual data type encountered at runtime is an <i>ArrayList</i>. Clearly, a direct lookup for <i>ArrayList</i> will do us no good as there’s no wrapper available for exactly this type. <p>This problem is handled via a CDI extension that observes all definitions of <i>@FacesDataModel</i> 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 <i>X</i> and <i>Y</i> from this collection, if an object of <i>X</i> is an instanceof an object of <i>Y</i>, <i>X</i> appears in the collection before <i>Y</i>. The collection's sorting is otherwise arbitrary. <p>With this collection available, the logic behind <i>@FacesDataModel</i> 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: <pre class="brush: java;"><br />getDataModelClassesMap(cdi).entrySet().stream()<br /> .filter(e -> e.getKey().isAssignableFrom(forClass))<br /> .findFirst() <br /> .ifPresent(<br /> e -> dataModel.add(<br /> cdi.select(<br /> e.getValue(),<br /> new FacesDataModelAnnotationLiteral(e.getKey())<br /> ).get())<br /> );<br /></pre> <p>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 <i>List</i> is found and used when the runtime type is <i>ArrayList</i>. <p>Before JSF 2.3 is finalised there are a couple of things that may still change. For instance, <i>Map</i> and <i>Iterable</i> have been added earlier as build-in wrappers, but could be refactored to be based on <i>@FacesDataModel</i> 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. <p>A more difficult and controversial change is to allow <i>@FacesDataModel</i> wrappers to override build-in wrappers. Currently it’s not possible to provide one own’s <i>List</i> wrapper, since <i>List</i> is build in and takes precedence. If <i>@FacesDataModel</i> 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 <i>@FacesDataModel</i> implementation for List, which would then take that user by surprise. <p>Things get even more complicated when both the new <i>Iterable</i> and <i>Map</i> would be implemented as <i>@FacesDataModel</i> AND <i>@FacesDataModel</i> would take precedence over the build-in types. In that case the <i>Iterable</i> wrapper would always match before the build-in <i>List</i> wrapper, making the latter unreachable. Now logically this would not matter as <i>Iterable</i> 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 <i>List</i> wrapper (in all honestly, such applications will likely fail too when switching JSF implementations). <p>Finally, doing totally away with the build-in wrappers and depending solely on <i>@FacesDataModel</i> 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”. <h3>Conclusion</h3><p>With <i>@FacesDataModel</i> custom DataModel wrappers can be registered, but those wrappers can not (yet) override any of the build-in types. <p><i>Arjan Tijms</i>Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com0tag:blogger.com,1999:blog-4498889353428710313.post-7866958129948428052015-06-03T07:58:00.000-07:002015-06-03T09:02:31.459-07:00OmniFaces 2.1 released!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. <p>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. <p>The easiest way to use OmniFaces 2.1 is via Maven by adding the following to pom.xml: <pre class="brush: xml;"><br />&lt;dependency&gt;<br /> &lt;groupId&gt;org.omnifaces&lt;/groupId&gt;<br /> &lt;artifactId&gt;omnifaces&lt;/artifactId&gt;<br /> &lt;version&gt;2.1&lt;/version&gt;<br />&lt;/dependency&gt;<br /></pre> <p>Alternatively the jars files can be downloaded <a href="http://central.maven.org/maven2/org/omnifaces/omnifaces/2.1/">directly</a>. <p>A complete overview of all that's new can be found on the <a href="http://showcase.omnifaces.org/whatsnew">what's new page</a>, and some more details can be found in <a href="http://balusc.blogspot.com/2015/06/omnifaces-21-release.html">BalusC's blogpost about this release</a>. <p>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 <a href="https://github.com/omnifaces/omnifaces/issues/133">Tomcat + OpenWebBeans (OWB)</a>. After a long discussion we finally got this to work, with special thanks to Mark Struberg and Ludovic Pénet. <p>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 <a href="https://github.com/omnifaces/omnifaces/blob/master/src/main/java/org/omnifaces/model/IterableDataModel.java">IterableDataModel</a> in order to <a href="http://jdevelopment.nl/jsf-23/#1103">support the Iterable interface in UIData and UIRepeat</a>). 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. <p>We will start planning soon for OmniFaces 2.2. Feature requests are always welcome ;) <p><i>Arjan Tijms</i>Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com0tag:blogger.com,1999:blog-4498889353428710313.post-56541250870113807142015-05-12T15:38:00.000-07:002015-05-12T15:51:30.553-07:00NEC's WebOTX - a commercial GlassFish derivativeIn a previous article we <a href="http://arjan-tijms.omnifaces.org/2013/09/diving-into-unknown-jeus-application.html">took a look at an obscure Java EE application server</a> 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. <p>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 <a href="http://jdevelopment.nl/hitachi-cosminexus-v10-silently-certified-java-ee-7">does not make it out here</a>. <p>Those servers are the following: <ol><li> <a href="https://java.zeef.com/jan.beernink#link_909343">NEC WebOTX</a><li> <a href="https://java.zeef.com/jan.beernink#link_909357">Hitachi Application Server</a><li> <a href="https://java.zeef.com/jan.beernink#link_909356">Fujitsu Interstage AS</a></ol> <p>In this article we're going to take a quick look at the first one of this list: NEC WebOTX. <p>While NEC does have an international English page where <a href="http://www.nec.com/en/global/prod/webotx/en/trial/evaluation.html">a trial can be downloaded</a> it only contains a very old version of WebOTX; 8.4, which implements Java EE 5. This file is called <a href="http://www.nec.com/en/global/prod/webotx/en/trial/media/otx84_win32bitE.exe">otx84_win32bitE.exe</a> and is about 92MB in size. <p>As with pretty much all of the Asian application servers, <a href="http://jpn.nec.com/webotx/download/trial/dl_start.html">the native language pages</a> 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 <i>OTXEXP91.exe</i> also once existed, but no other versions were found. <p>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 <a href="http://nec.com/en/global/prod/webotx/en/trial/media/otx84_win_setup_card_E.pdf">English instructions for the older WebOTX 8.4</a> 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 <a href="http://arjan-tijms.omnifaces.org/2015/04/testing-jaspic-11-on-ibm-liberty-ee-7.html">download & unzip, start server</a>), but after a while WebOTX was installed in <i>e:\webotx</i>. <h3> Jar and file comparison </h3> <p>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 <a href="http://arjan-tijms.omnifaces.org/2014/05/implementation-components-used-by.html">what implementation components a particular server is using</a>. <p>Surprisingly, the folder structure somewhat resembled that of GlassFish, but with some extra directories. E.g. <table border="1"><tr><td>GlassFish 3.1.2.2 main dir</td><td>WebOTX 9.2 main dir</td></tr><tr> <td><a href="http://3.bp.blogspot.com/-Qxh8T7aN3OM/VUqO6d-s8sI/AAAAAAAAALo/aZUZ4QCAyJI/s1600/glassfish_main_dir.png" imageanchor="1" ><img border="0" src="http://3.bp.blogspot.com/-Qxh8T7aN3OM/VUqO6d-s8sI/AAAAAAAAALo/aZUZ4QCAyJI/s320/glassfish_main_dir.png" /></a></td> <td><a href="http://1.bp.blogspot.com/-5EXN7l3nZgI/VUqPsCYZgmI/AAAAAAAAALw/vjZ8_ncaQTQ/s1600/webotx_main_dir.png" imageanchor="1" ><img border="0" src="http://1.bp.blogspot.com/-5EXN7l3nZgI/VUqPsCYZgmI/AAAAAAAAALw/vjZ8_ncaQTQ/s320/webotx_main_dir.png" /></a></td></tr></table><p><small>&nbsp;</small> <p>Looking at the <i>modules</i> directory in fact did make it clear that WebOTX is in fact strongly based on GlassFish: <table border="1"><tr><td>GlassFish 3.1.2.2 modules dir</td><td>WebOTX 9.2 modules dir</td></tr><tr> <td><a href="http://4.bp.blogspot.com/-yzH-QngbFpE/VUqQT-cdR1I/AAAAAAAAAL4/gnfXxkltxes/s1600/glassfish_modules_dir.png" imageanchor="1" ><img border="0" src="http://4.bp.blogspot.com/-yzH-QngbFpE/VUqQT-cdR1I/AAAAAAAAAL4/gnfXxkltxes/s320/glassfish_modules_dir.png" /></a></td> <td><a href="http://4.bp.blogspot.com/-tA1ZzoiV0rg/VUqQgi1sbSI/AAAAAAAAAMA/sGJHryHYTZI/s1600/webotx_modules_dir.png" imageanchor="1" ><img border="0" src="http://4.bp.blogspot.com/-tA1ZzoiV0rg/VUqQgi1sbSI/AAAAAAAAAMA/sGJHryHYTZI/s320/webotx_modules_dir.png" /></a></td></tr></table><p><small>&nbsp;</small> <p>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 <i>glassfish-*</i> and <i>gf-*</i> jars. None of these are present in WebOTX, although for many similar ones are present but just prefixed by <i>webotx-</i> as shown below: <table border="1"><tr><td>glassfish- prefixed jars</td><td>webotx- prefixed jars</td></tr><tr> <td><a href="http://1.bp.blogspot.com/-43HyA_RKZaY/VUvqtqcJBlI/AAAAAAAAAMk/uZoasQs1DIo/s1600/glassfish-prefix-jars.png" imageanchor="1" ><img border="0" src="http://1.bp.blogspot.com/-43HyA_RKZaY/VUvqtqcJBlI/AAAAAAAAAMk/uZoasQs1DIo/s320/glassfish-prefix-jars.png" /></a></td> <td><a href="http://1.bp.blogspot.com/-xpYhOjQtQdY/VUvq1UK6zGI/AAAAAAAAAMs/JMBtcVOD6uQ/s1600/webotx-prefixed-jars.png" imageanchor="1" ><img border="0" src="http://1.bp.blogspot.com/-xpYhOjQtQdY/VUvq1UK6zGI/AAAAAAAAAMs/JMBtcVOD6uQ/s320/webotx-prefixed-jars.png" /></a></td></tr></table><p><small>&nbsp;</small> <p>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: <table border="1"><tr><td>glassfish.jar</td><td>webotx.jar</td></tr><tr> <td><a href="http://3.bp.blogspot.com/-jOJ2wTaQ2vQ/VUvuh7FJyWI/AAAAAAAAANQ/e1nMDdbV7PA/s1600/glassfish-jar-files.png" imageanchor="1" ><img border="0" src="http://3.bp.blogspot.com/-jOJ2wTaQ2vQ/VUvuh7FJyWI/AAAAAAAAANQ/e1nMDdbV7PA/s320/glassfish-jar-files.png" /></a></td> <td><a href="http://4.bp.blogspot.com/-C5MatA3l6So/VUvuTmq7_4I/AAAAAAAAANI/pJxS-okzl6Q/s1600/webotx-jar-files.png" imageanchor="1" ><img border="0" src="http://4.bp.blogspot.com/-C5MatA3l6So/VUvuTmq7_4I/AAAAAAAAANI/pJxS-okzl6Q/s320/webotx-jar-files.png" /></a></td></tr></table><p><small>&nbsp;</small> <p>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: <table border="1"><tr><td>glassfish jersey-core.jar</td><td>webotx jersey-core.jar</td></tr><tr> <td><a href="http://1.bp.blogspot.com/-rLmH1VnEkoc/VU56ZA0xpOI/AAAAAAAAANk/eyVUo-zU8qg/s1600/glassfish-jersey-core.png" imageanchor="1" ><img border="0" src="http://1.bp.blogspot.com/-rLmH1VnEkoc/VU56ZA0xpOI/AAAAAAAAANk/eyVUo-zU8qg/s320/glassfish-jersey-core.png" /></a></td> <td><a href="http://1.bp.blogspot.com/-xj6kvKyZ3Iw/VU56fXJK1LI/AAAAAAAAANs/LRDznccNgvs/s1600/webotx-jersey.core.png" imageanchor="1" ><img border="0" src="http://1.bp.blogspot.com/-xj6kvKyZ3Iw/VU56fXJK1LI/AAAAAAAAANs/LRDznccNgvs/s320/webotx-jersey.core.png" /></a></td></tr></table><p><small>&nbsp;</small> <p>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: <div style="font-size:70%;"><pre class="brush: xml;"><br />&lt;project&gt;<br /> &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;<br /> &lt;!-- upds start 20121122 org.glassfish to com.nec.webotx.as --&gt;<br /> &lt;groupId&gt;com.nec.webotx.as&lt;/groupId&gt;<br /> &lt;!-- upds end 20121122 org.glassfish to com.nec.webotx.as --&gt;<br /> &lt;artifactId&gt;javax.faces&lt;/artifactId&gt;<br /> &lt;version&gt;9.2.1&lt;/version&gt;<br /> &lt;packaging&gt;jar&lt;/packaging&gt;<br /> &lt;name&gt;<br /> Oracle's implementation of the JSF 2.1 specification.<br /> &lt;/name&gt;<br /> &lt;description&gt;<br /> This is the master POM file for Oracle's Implementation of the JSF 2.1 Specification.<br /> &lt;/description&gt;<br /></pre></div> With the MANIFEST.FM containing this: <div style="font-size:70%;"><pre class="brush: xml;"><br />Implementation-Title: Mojarra<br />Implementation-Version: 9.2.1<br />Tool: Bnd-0.0.249<br />DSTAMP: 20131217<br />TODAY: December 17 2013<br />Bundle-Name: Mojarra JSF Implementation 9.2.1 (20131217-1350) https://<br /> swf0200036.swf.nec.co.jp/app/svn/WebOTX-SWFactory/dev/mojarra/branche<br /> s/mojarra2.1.26@96979<br />TSTAMP: 1350<br />DocName: Mojarra Implementation Javadoc<br />Implementation-Vendor: Oracle America, Inc.<br /></pre></div> <p><small>&nbsp;</small><p><h3> Trying out the server </h3> <p>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 <i>http://localhost</i> results in the following screen: <p><a href="http://3.bp.blogspot.com/-AxGBnbnPhFE/VVJv7pbyDqI/AAAAAAAAAOA/S92cjGK_pm8/s1600/webotx-localhost-default.png" imageanchor="1" ><img border="0" src="http://3.bp.blogspot.com/-AxGBnbnPhFE/VVJv7pbyDqI/AAAAAAAAAOA/S92cjGK_pm8/s320/webotx-localhost-default.png" /></a> <p>The admin interface is present on port 5858. For some reason the initial login screen asks for very specific browser versions though: <p><a href="http://3.bp.blogspot.com/-cy2b0zCBpVY/VVJ0oGfbBQI/AAAAAAAAAOM/for9MlSEUko/s1600/webotx-login.png" imageanchor="1" ><img border="0" src="http://3.bp.blogspot.com/-cy2b0zCBpVY/VVJ0oGfbBQI/AAAAAAAAAOM/for9MlSEUko/s320/webotx-login.png" /></a> <p>After logging in with username "admin", password "adminadmin", we're presented with a colorful admin console: <p><a href="http://3.bp.blogspot.com/-rwii3y50lW8/VVJ17L0TnqI/AAAAAAAAAOY/TenHpNQl6HI/s1600/webotx-admin-console.png" imageanchor="1" ><img border="0" src="http://3.bp.blogspot.com/-rwii3y50lW8/VVJ17L0TnqI/AAAAAAAAAOY/TenHpNQl6HI/s320/webotx-admin-console.png" /></a> <p>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. <p>I tried to upload a .war file of the <a href="http://showcase.omnifaces.org">OmniFaces showcase</a>, 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: <p><a href="http://3.bp.blogspot.com/-pcvs3km-nvA/VVJ3E9esZMI/AAAAAAAAAOg/AV3sopIRilo/s1600/webotx-upload-archive.png" imageanchor="1" ><img border="0" src="http://3.bp.blogspot.com/-pcvs3km-nvA/VVJ3E9esZMI/AAAAAAAAAOg/AV3sopIRilo/s320/webotx-upload-archive.png" /></a> <p>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 <i>http://localhost</i> again the OmniFaces showcase home screen was displayed: <p><a href="http://4.bp.blogspot.com/-CBjaNQF5-pY/VVJ3xMRi6aI/AAAAAAAAAOo/QVLYAGaQP84/s1600/weboxt-omnifaces-showcase.png" imageanchor="1" ><img border="0" src="http://4.bp.blogspot.com/-CBjaNQF5-pY/VVJ3xMRi6aI/AAAAAAAAAOo/QVLYAGaQP84/s320/weboxt-omnifaces-showcase.png" /></a> <p>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 ;) <p>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. <h3> Conclusion </h3> <p>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 <a href="http://adam-bien.com/roller/abien/entry/glassfish_became_a_killer_appserver">stopped commercial support</a> 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 <a href="http://payara.co.uk">Payara</a> there remains more interest in the GlassFish code beyond being "merely" an example for other vendors. <p>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. <p>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. <p><i>Arjan Tijms</i> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com2tag:blogger.com,1999:blog-4498889353428710313.post-47658736972472003192015-05-04T13:12:00.001-07:002015-05-04T13:12:49.463-07:00OmniFaces 2.1-RC1 has been released!We are proud to announce that OmniFaces 2.1 release candidate 1 has been made available for testing. <p>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. <p>A full list of what's new and changed is available <a href="http://snapshot.omnifaces.org/whatsnew">here</a>. <p>OmniFaces 2.1 RC1 can be tested by adding the following dependency to your pom.xml: <pre class="brush: xml; gutter: false;"><br />&lt;dependency><br /> &lt;groupId>org.omnifaces&lt;/groupId><br /> &lt;artifactId>omnifaces&lt;/artifactId><br /> &lt;version>2.1-RC1&lt;/version><br />&lt;/dependency><br /></pre> <p>Alternatively the jars files can be downloaded <a href="http://central.maven.org/maven2/org/omnifaces/omnifaces/2.1-RC1/">directly</a>. <p>For the 1.x branch the coordinates are: <pre class="brush: xml; gutter: false;"><br />&lt;dependency><br /> &lt;groupId>org.omnifaces&lt;/groupId><br /> &lt;artifactId>omnifaces&lt;/artifactId><br /> &lt;version>1.11-RC1&lt;/version><br />&lt;/dependency><br /></pre> This one too can be downloaded <a href="http://central.maven.org/maven2/org/omnifaces/omnifaces/1.11-RC1/">directly</a>. <p>If no major bugs surface we hope to release OmniFaces 2.1 final soon. <p><i>Arjan Tijms</i>Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com1tag:blogger.com,1999:blog-4498889353428710313.post-24317274694476797002015-04-22T16:09:00.000-07:002015-08-05T14:05:49.011-07:00Testing JASPIC 1.1 on IBM Liberty EE 7 beta 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. <p>The initial version of Liberty implemented only a seemingly random assortment of Java EE APIs, but the second version <a href="http://arjan-tijms.omnifaces.org/2013/06/trying-liberty-855.html">that we looked at last year</a> 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. <p>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. <p>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. <p>We started by downloading Liberty from the <a href="https://developer.ibm.com/wasdev/downloads/liberty-profile-beta">beta download page</a>. 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. <p>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 :) <p>We downloaded the Java EE 7 archive, <a href="https://developer.ibm.com/wasdev/downloads/liberty-profile-beta/wlp/beta/wlp-beta-javaee7-2015.4.0.0.zip">wlp-beta-javaee7-2015.4.0.0.zip</a>, 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. <p>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. <p>(<i><b>UPDATE</b>: IBM responded right away by removing the redundant step mentioned by the download page</i>) <p>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 <i>&lt;feature&gt;javaee-7.0&lt;/feature&gt;</i>. 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: <i>&lt;feature&gt;jaspic-1.1&lt;/feature&gt;</i>. Hopefully these two issues are just packaging errors and will be resolved in the next beta or at least in the final version. <p>On to trying out JASPIC, we unfortunately learned that by default JASPIC doesn't really work as it should. Liberty inherited a <a href="http://stackoverflow.com/q/27686626/472792">spec compliance issue from WebSphere 8.x</a> 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. <p>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 <a href="https://www.ibm.com/developerworks/rfe/execute?use_case=viewRfe&CR_ID=69687">an open issue</a> for this in IBM's tracker. Another problem is that the group to role mapping file <a href="http://stackoverflow.com/q/29524920/472792">can only be supplied by the application when using an EAR archive</a>. 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 <a href="https://www.ibm.com/developerworks/rfe/execute?use_case=viewRfe&CR_ID=69688">an issue filed</a> to remedy this. <p>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 <a href="https://developer.ibm.com/wasdev/docs/creating-a-custom-user-registry-as-a-liberty-user-feature">how to do this</a>, but unfortunately it's not giving exact instructions but merely outlines the process. The structure is also not entirely logical. <p>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. <p>Even though it's outdated, IBM's general documentation on <a href="https://developer.ibm.com/wasdev/docs/article_creatingfeatures">how to create a Liberty feature</a> is much clearer. With those two articles side by side and cross checking it with <a href="https://developer.ibm.com/wasdev/downloads/#asset/samples-Custom_User_Registry">the source code of the example</a> 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 <a href="https://developer.ibm.com/wasdev/blog/repo/productsample_customuserregistrysample">the link</a> 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. <p>The source code of the actual user registry is as follows: <div style="font-size:80%;"><pre class="brush: java;"><br />package noopregistrybundle;<br /><br />import static java.util.Collections.emptyList;<br /><br />import java.rmi.RemoteException;<br />import java.security.cert.X509Certificate;<br />import java.util.ArrayList;<br />import java.util.List;<br />import java.util.Properties;<br /><br />import javax.naming.InvalidNameException;<br />import javax.naming.ldap.LdapName;<br />import javax.naming.ldap.Rdn;<br /><br />import com.ibm.websphere.security.CertificateMapFailedException;<br />import com.ibm.websphere.security.CertificateMapNotSupportedException;<br />import com.ibm.websphere.security.CustomRegistryException;<br />import com.ibm.websphere.security.EntryNotFoundException;<br />import com.ibm.websphere.security.NotImplementedException;<br />import com.ibm.websphere.security.PasswordCheckFailedException;<br />import com.ibm.websphere.security.Result;<br />import com.ibm.websphere.security.UserRegistry;<br />import com.ibm.websphere.security.cred.WSCredential;<br /><br />public class NoopUserRegistry implements UserRegistry {<br /><br /> @Override<br /> public void initialize(Properties props) throws CustomRegistryException, RemoteException {<br /> }<br /><br /> @Override<br /> public String checkPassword(String userSecurityName, String password) throws PasswordCheckFailedException, CustomRegistryException, RemoteException {<br /> return userSecurityName;<br /> }<br /><br /> @Override<br /> public String mapCertificate(X509Certificate[] certs) throws CertificateMapNotSupportedException, CertificateMapFailedException, CustomRegistryException, RemoteException {<br /> try {<br /> for (X509Certificate cert : certs) {<br /> for (Rdn rdn : new LdapName(cert.getSubjectX500Principal().getName()).getRdns()) {<br /> if (rdn.getType().equalsIgnoreCase("CN")) {<br /> return rdn.getValue().toString();<br /> }<br /> }<br /> }<br /> } catch (InvalidNameException e) {<br /> }<br /><br /> throw new CertificateMapFailedException("No valid CN in any certificate");<br /> }<br /><br /> @Override<br /> public String getRealm() throws CustomRegistryException, RemoteException {<br /> return "customRealm"; // documentation says can be null, but should really be non-null!<br /> }<br /><br /> @Override<br /> public Result getUsers(String pattern, int limit) throws CustomRegistryException, RemoteException {<br /> return emptyResult();<br /> }<br /><br /> @Override<br /> public String getUserDisplayName(String userSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException {<br /> return userSecurityName;<br /> }<br /><br /> @Override<br /> public String getUniqueUserId(String userSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException {<br /> return userSecurityName;<br /> }<br /><br /> @Override<br /> public String getUserSecurityName(String uniqueUserId) throws EntryNotFoundException, CustomRegistryException, RemoteException {<br /> return uniqueUserId;<br /> }<br /><br /> @Override<br /> public boolean isValidUser(String userSecurityName) throws CustomRegistryException, RemoteException {<br /> return true;<br /> }<br /><br /> @Override<br /> public Result getGroups(String pattern, int limit) throws CustomRegistryException, RemoteException {<br /> return emptyResult();<br /> }<br /><br /> @Override<br /> public String getGroupDisplayName(String groupSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException {<br /> return groupSecurityName;<br /> }<br /><br /> @Override<br /> public String getUniqueGroupId(String groupSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException {<br /> return groupSecurityName;<br /> }<br /><br /> @Override<br /> public List&lt;String&gt; getUniqueGroupIds(String uniqueUserId) throws EntryNotFoundException, CustomRegistryException, RemoteException {<br /> return new ArrayList&lt;&gt;(); // Apparently needs to be mutable<br /> }<br /><br /> @Override<br /> public String getGroupSecurityName(String uniqueGroupId) throws EntryNotFoundException, CustomRegistryException, RemoteException {<br /> return uniqueGroupId;<br /> }<br /><br /> @Override<br /> public boolean isValidGroup(String groupSecurityName) throws CustomRegistryException, RemoteException {<br /> return true;<br /> }<br /><br /> @Override<br /> public List&lt;String&gt; getGroupsForUser(String groupSecurityName) throws EntryNotFoundException, CustomRegistryException, RemoteException {<br /> return emptyList();<br /> }<br /><br /> @Override<br /> public Result getUsersForGroup(String paramString, int paramInt) throws NotImplementedException, EntryNotFoundException, CustomRegistryException, RemoteException {<br /> return emptyResult();<br /> }<br /><br /> @Override<br /> public WSCredential createCredential(String userSecurityName) throws NotImplementedException, EntryNotFoundException, CustomRegistryException, RemoteException {<br /> return null;<br /> }<br /> <br /> private Result emptyResult() {<br /> Result result = new Result();<br /> result.setList(emptyList());<br /> return result;<br /> }<br />}<br /></pre></div> <p>There were two small caveats here. The first is that <a href="http://www-01.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/tsec_users.html?cp=SSAW57_8.5.5%2F3-8-2-33-2-1-2-2">the documentation</a> for <i>getRealm</i> says it may return <i>null</i> and that "customRealm" will be used as the default then. But when you actually return <i>null</i> authentication will fail with many null pointer exceptions appearing in the log. The second is that <i>getUniqueGroupIds()</i> has to return a mutable collection. If <i>Collections#emptyList</i> 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. <p>The <i>Activator</i> class that's mentioned in the article referenced above looks as follows: <div style="font-size:90%;"><pre class="brush: java;"><br />package noopregistrybundle;<br /><br />import static org.osgi.framework.Constants.SERVICE_PID;<br /><br />import java.util.Dictionary;<br />import java.util.Hashtable;<br /><br />import org.osgi.framework.BundleActivator;<br />import org.osgi.framework.BundleContext;<br />import org.osgi.framework.ServiceRegistration;<br />import org.osgi.service.cm.ConfigurationException;<br />import org.osgi.service.cm.ManagedService;<br /><br />import com.ibm.websphere.security.UserRegistry;<br /><br />public class Activator extends NoopUserRegistry implements BundleActivator, ManagedService {<br /><br /> private static final String CONFIG_PID = "noopUserRegistry";<br /> <br /> private ServiceRegistration&lt;ManagedService&gt; managedServiceRegistration;<br /> private ServiceRegistration&lt;UserRegistry&gt; userRegistryRegistration;<br /><br /> @SuppressWarnings({ "rawtypes", "unchecked" })<br /> Hashtable getDefaults() {<br /> Hashtable defaults = new Hashtable();<br /> defaults.put(SERVICE_PID, CONFIG_PID);<br /> return defaults;<br /> }<br /><br /> @SuppressWarnings("unchecked")<br /> public void start(BundleContext context) throws Exception {<br /> managedServiceRegistration = context.registerService(ManagedService.class, this, getDefaults());<br /> userRegistryRegistration = context.registerService(UserRegistry.class, this, getDefaults());<br /> }<br /> <br /> @Override<br /> public void updated(Dictionary&lt;String, ?&gt; properties) throws ConfigurationException {<br /><br /> }<br /><br /> public void stop(BundleContext context) throws Exception {<br /> if (managedServiceRegistration != null) {<br /> managedServiceRegistration.unregister();<br /> managedServiceRegistration = null;<br /> }<br /> if (userRegistryRegistration != null) {<br /> userRegistryRegistration.unregister();<br /> userRegistryRegistration = null;<br /> }<br /> }<br />}<br /></pre></div> <p>Here we learned what that cryptic "Register the services" instruction from the article meant; it are the two calls to <i>context.registerService</i> here. Surely something that's easy to guess, or isn't it? <p>Finally a <i>MANIFEST.FM</i> 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: <div style="font-size:90%;"><pre class="brush: java;"><br />Manifest-Version: 1.0<br />Bundle-ManifestVersion: 2<br />Bundle-Name: NoopRegistryBundle<br />Bundle-SymbolicName: NoopRegistryBundle<br />Bundle-Version: 1.0.0.qualifier<br />Bundle-Activator: noopregistrybundle.Activator<br />Import-Package: com.ibm.websphere.security;version="1.1.0",<br /> javax.naming,<br /> javax.naming.ldap,<br /> org.osgi.service.cm,<br /> org.osgi.framework<br />Bundle-RequiredExecutionEnvironment: JavaSE-1.7<br />Export-Package: noopregistrybundle<br /></pre></div> <p>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. <p>The final step consisted of adding the noop user registry to Liberty's <i>server.xml</i>, which looked as follows: <div style="font-size:90%;"><pre class="brush: xml;"><br />&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />&lt;server description="new server"&gt;<br /><br /> &lt;featureManager&gt;<br /> &lt;feature&gt;javaee-7.0&lt;/feature&gt;<br /> &lt;feature&gt;jaspic-1.1&lt;/feature&gt;<br /> &lt;feature&gt;localConnector-1.0&lt;/feature&gt;<br /> &lt;feature&gt;usr:NoopRegistryFeature&lt;/feature&gt;<br /> &lt;/featureManager&gt;<br /><br /> &lt;httpEndpoint httpPort="9080" httpsPort="9443" id="defaultHttpEndpoint"/&gt;<br /><br /> &lt;noopUserRegistry/&gt;<br />&lt;/server&gt;<br /></pre></div> <p>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 <a href="https://github.com/javaee-samples/javaee7-samples">Java EE 7 samples project</a>. These tests have been used by various other server vendors already and give a basic impression of what things work and do not work. <p>The tests had to be <a href="https://github.com/javaee-samples/javaee7-samples/commit/eb7483717940929663485054ec127bdaa7f07cb1">adjusted for Liberty</a> because of its requirement to add an EAR wrapper that hosts the mandated group to role mapping. <p>After running the tests, the following failures were reported: <small><table border="1" style="font-size: 80%;"> <tr style="background-color:LightGray;"><th>Test</th> <th>Class</th> <th>Comment</th></tr> <tr><td>testPublicPageNotRememberLogin </td> <td><small>org.javaee7.jaspic.basicauthentication.BasicAuthenticationPublicTest </small></td> <td> </td></tr> <tr><td>testPublicPageLoggedin </td> <td><small>org.javaee7.jaspic.basicauthentication.BasicAuthenticationPublicTest </small></td> <td> </td></tr> <tr><td>testProtectedAccessIsStateless </td> <td><small>org.javaee7.jaspic.basicauthentication.BasicAuthenticationStatelessTest </small></td> <td> </td></tr> <tr><td>testPublicServletWithLoginCallingEJB </td> <td><small>org.javaee7.jaspic.ejbpropagation.ProtectedEJBPropagationTest </small></td> <td> </td></tr> <tr><td>testProtectedServletWithLoginCallingEJB </td> <td><small>org.javaee7.jaspic.ejbpropagation.PublicEJBPropagationLogoutTest</small></td> <td> </td></tr> <tr><td>testProtectedServletWithLoginCallingEJB </td> <td><small>org.javaee7.jaspic.ejbpropagation.PublicEJBPropagationTest </small></td> <td> </td></tr> <tr><td>testLogout </td> <td><small>org.javaee7.jaspic.lifecycle.AuthModuleMethodInvocationTest</small></td> <td>SAM method cleanSubject not called, but should have been </td></tr> <tr><td>testJoinSessionIsOptional </td> <td><small>org.javaee7.jaspic.registersession.RegisterSessionTest </small></td> <td> </td></tr> <tr><td>testRemembersSession </td> <td><small> org.javaee7.jaspic.registersession.RegisterSessionTest</small></td> <td> </td></tr> <tr><td>testResponseWrapping </td> <td><small>org.javaee7.jaspic.wrapping.WrappingTest </small></td> <td> Response wrapped by SAM did not arrive in Servlet</td></tr> <tr><td>testRequestWrapping </td> <td><small>org.javaee7.jaspic.wrapping.WrappingTest </small></td> <td> Request wrapped by SAM did not arrive in Servlet</td></tr> </table></small> <p>Specifically the EJB, "logout calls cleanSubject" & register session (both <a href="http://arjan-tijms.omnifaces.org/2013/04/whats-new-in-java-ee-7s-authentication.html">new JASPIC 1.1 features</a>) and request/response wrapper tests failed. <p>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). <h3> First Java EE 7 production ready server? </h3> <p>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 <a href="http://arjan-tijms.omnifaces.org/2014/10/java-ee-process-cycles-and-server.html">implementation cycle</a> 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). <p>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). <h3> Conclusion </h3> <p>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. <p>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 <a href="https://github.com/javaee-samples/javaee7-samples/issues/263">already looking</a> at the JASPIC issues. <p>To summarize the good and not so good points: <p><b>Good</b><ul><li> Runs on all operating systems (no special IBM JDK required) <li> Monthly betas of EE 7 server <li> Liberty to support Java EE 7 full profile <li> Possibly on its way to become the first production ready EE 7 server <li> Public download page without required registration <li> Very good file size for full profile (100MB) <li> Extremely easy "download - unzip - ./server start" experience </ul> <p><b>Not (yet) so good</b><ul><li> <s>Download page lists totally unnecessary step asking to "create a server"</s> (update: now fixed by IBM) <li> <s>Wrong file permissions in archive for usage on Linux; executable attribute missing on bin/server</s> (update: now fixed by IBM) <li> Wrong configuration of <i>server.xml</i>; both web and full profile by default configured as JSP/Servlet only <li> <s>"javaee-7.0" feature in <i>server.xml</i> doesn't imply JASPIC and JACC, while both are part of Java EE</s> (update: now fixed by IBM) <li> JASPIC runtime tries to validate usernames/groups in internal identity store (violation of JASPIC spec) <li> Mandatory group to role mapping, even when this is not needed <li> Mandatory usage of EAR archive when group to role mapping has to be provided by the application <li> Not all JASPIC features implemented yet (but remember that we looked at a beta version) </ul> <p><i>Arjan Tijms</i>Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com45tag:blogger.com,1999:blog-4498889353428710313.post-62597705101423286482015-04-02T05:12:00.000-07:002017-05-18T05:49:04.043-07:00How Java EE translates web.xml constraints to Permission instancesIt's a well known fact that in Java EE security one can specify security constraints in <i>web.xml</i>. 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 <a href="http://docs.oracle.com/javase/8/docs/api/java/security/Permission.html">Permission</a> class. The specifications responsible for this are Servlet and JACC. This article shows a simple example of what this translation looks like. <p><h4> Web.xml constraints </h4> <p>We're putting the following constraints in <i>web.xml</i>: <pre class="brush: xml;"><br />&lt;security-constraint&gt;<br /> &lt;web-resource-collection&gt;<br /> &lt;web-resource-name&gt;Forbidden Pattern&lt;/web-resource-name&gt;<br /> &lt;url-pattern&gt;/forbidden/*&lt;/url-pattern&gt;<br /> &lt;/web-resource-collection&gt;<br /> &lt;auth-constraint/&gt;<br />&lt;/security-constraint&gt;<br /><br />&lt;security-constraint&gt;<br /> &lt;web-resource-collection&gt;<br /> &lt;web-resource-name&gt;Protected Pattern&lt;/web-resource-name&gt;<br /> &lt;url-pattern&gt;/protected/*&lt;/url-pattern&gt;<br /> &lt;/web-resource-collection&gt;<br /> &lt;auth-constraint&gt;<br /> &lt;role-name&gt;architect&lt;/role-name&gt;<br /> &lt;role-name&gt;administrator&lt;/role-name&gt;<br /> &lt;/auth-constraint&gt;<br />&lt;/security-constraint&gt;<br /><br />&lt;security-constraint&gt;<br /> &lt;web-resource-collection&gt;<br /> &lt;web-resource-name&gt;Protected Exact&lt;/web-resource-name&gt;<br /> &lt;url-pattern&gt;/adminservlet&lt;/url-pattern&gt;<br /> &lt;/web-resource-collection&gt;<br /> &lt;auth-constraint&gt;<br /> &lt;role-name&gt;administrator&lt;/role-name&gt;<br /> &lt;/auth-constraint&gt;<br />&lt;/security-constraint&gt;<br /><br />&lt;security-role&gt;<br /> &lt;role-name&gt;architect&lt;/role-name&gt;<br />&lt;/security-role&gt;<br />&lt;security-role&gt;<br /> &lt;role-name&gt;administrator&lt;/role-name&gt;<br />&lt;/security-role&gt;<br /></pre> <p> <p><h4> Java Permissions </h4> <p>Given the above shown constraints in <i>web.xml</i> the following WebResourcePermission instances will be generated, in 3 collections as shown below. For brevity only WebResourcePermission is shown. The other types are omitted. <p><b>Excluded</b><ul><li>WebResourcePermission "/forbidden/*" </li></ul> <p><b>Unchecked</b><ul><li>WebResourcePermission "/:/adminservlet:/protected/*:/forbidden/*" </li></ul> <p><b>Per Role</b><ul><li> architect <ul><li>WebResourcePermission "/protected/*"</li></ul> </li><li> administrator <ul> <li>WebResourcePermission "/protected/*"</li> <li>WebResourcePermission "/adminservlet"</li> </ul> </li></ul> <p>Below is a 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. <p><hr><small> Java EE will generate 3 types of Permission instances when translating constraints expressed in web.xml; <a href="http://docs.oracle.com/javaee/7/api/javax/security/jacc/WebRoleRefPermission.html">WebRoleRefPermission</a>, <a href="http://docs.oracle.com/javaee/7/api/javax/security/jacc/WebUserDataPermission.html">WebUserDataPermission</a> and <a href="http://docs.oracle.com/javaee/7/api/javax/security/jacc/WebResourcePermission.html">WebResourcePermission</a>. <p><h4>WebRoleRefPermission</h4> 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. <p><h4>WebUserDataPermission</h4> 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 &lt;user-data-constraint&gt; element in <i>web.xml</i>, which we have omitted here. <p><h4>WebResourcePermission</h4> The web resource permission is about the actual access to a resource. This can be specified using the &lt;web-resource-collection&gt; element in <i>web.xml</i>, which we have used in the example above. </small><hr> <p>So let's take a look at what's going on here. <p>Our first <i>web.xml</i> 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 <i>auth-constraint</i> element. This was translated to Java code by means of putting a <i>WebResourcePermission</i> with the pattern "/forbidden/*" in the "Excluded" collection. Although there are some differences, this is a reasonably direct translation from the XML form. <p>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). <p>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 <i>"/:/adminservlet:/protected/*:/forbidden/*"</i> 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. <p>The next two constraints that we showed in <i>web.xml</i> 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 <i>{role, permission}</i> 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 <i>role</i> the key and <i>permission</i> 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. <p><h4>Obtaining the generated Permissions</h4> <p>There is unfortunately no API available in Java EE to directly obtain the generated <i>Permission</i> instances. Instead, one has to install a JACC provider that is called by the container for each individual <i>Permission</i> that is generated. A ready to use provider was given in a <a href="http://arjan-tijms.omnifaces.org/2015/03/java-ee-authorization-jacc-revisited.html">previous article</a>, but as we saw <a href="http://arjan-tijms.omnifaces.org/2015/01/java-ee-authorization-jacc-revisited.html">before</a> they are <a href="https://developer.jboss.org/thread/254106">not entirely trivial</a> to install. <p><h4>Conclusion</h4> <p>We've shown a few simple <i>web.xml</i> based security constraints and saw how they translated to Java <i>Permission</i> instances. <p>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. <p><i>Arjan Tijms</i>Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com1tag:blogger.com,1999:blog-4498889353428710313.post-85407162600206180142015-03-19T16:29:00.000-07:002015-03-20T03:58:17.161-07:00Java EE authorization - JACC revisited part IIIThis is the third and final part of a series where we revisit JACC after taking an <a href="http://arjan-tijms.omnifaces.org/2014/03/implementing-container-authorization-in.html">initial look</a> at it last year. <p>In the <a href="http://arjan-tijms.omnifaces.org/2014/12/java-ee-authorization-jacc-revisited.html">first part</a> we mainly looked at various role mapping strategies, while the main topic of the <a href="http://arjan-tijms.omnifaces.org/2015/01/java-ee-authorization-jacc-revisited.html">second part</a> was obtaining the container specific role mapper and the container specific way of how a JACC provider is deployed. <p>In this third and final part we'll be bringing it all together and present a fully working JACC provider for a single application module (e.g. a single war). <p><h3>Architecture</h3><p> As explained <a href="http://arjan-tijms.omnifaces.org/2014/03/implementing-container-authorization-in.html">before</a>, implementing a JACC provider requires implementing three classes: <ol><li> PolicyConfigurationFactory </li><li> PolicyConfiguration</li><li> Policy </li></ol> Zooming into these, the following is what is more accurately required to be implemented: <ol><li> A factory that provides an object that collects permissions </li><li> A state machine that controls the life-cyle of this permission collector</li><li> Linking permissions of multiple modules and utilities </li><li> Collecting and managing permissions </li><li> Processing permissions after collecting </li><li> An "authorization module" using permissions for authorization decisions </li></ol> <p>In the implementation given <a href="http://arjan-tijms.omnifaces.org/2014/03/implementing-container-authorization-in.html">before</a> we put all this functionality in the specified three classes. Here we'll split out each item to a separate class (we'll skip linking though, which is only required for EARs where security constraints are defined in multiple modules). This will result in more classes in total, but each class is hopefully easier to understand. <p><h4>A factory that provides an object that collects permissions </h4><p> The factory is largely as given <a href="http://arjan-tijms.omnifaces.org/2014/03/implementing-container-authorization-in.html">earlier</a>, but contains a few fixes and makes use of the state machine that is shown below. <div style="font-size:90%;"><pre class="brush: java;"><br />import static javax.security.jacc.PolicyContext.getContextID;<br /><br />import java.util.concurrent.ConcurrentHashMap;<br />import java.util.concurrent.ConcurrentMap;<br /><br />import javax.security.jacc.PolicyConfiguration;<br />import javax.security.jacc.PolicyConfigurationFactory;<br />import javax.security.jacc.PolicyContextException;<br /><br />public class TestPolicyConfigurationFactory extends PolicyConfigurationFactory {<br /> <br /> private static final ConcurrentMap&lt;String, TestPolicyConfigurationStateMachine&gt; configurators = new ConcurrentHashMap&lt;&gt;();<br /><br /> @Override<br /> public PolicyConfiguration getPolicyConfiguration(String contextID, boolean remove) throws PolicyContextException {<br /> <br /> if (!configurators.containsKey(contextID)) {<br /> configurators.putIfAbsent(contextID, new TestPolicyConfigurationStateMachine(new TestPolicyConfiguration(contextID)));<br /> }<br /> <br /> TestPolicyConfigurationStateMachine testPolicyConfigurationStateMachine = configurators.get(contextID);<br /> <br /> if (remove) {<br /> testPolicyConfigurationStateMachine.delete();<br /> }<br /> <br /> // According to the contract of getPolicyConfiguration() every PolicyConfiguration returned from here<br /> // should always be transitioned to the OPEN state.<br /> testPolicyConfigurationStateMachine.open();<br /> <br /> return testPolicyConfigurationStateMachine;<br /> }<br /> <br /> @Override<br /> public boolean inService(String contextID) throws PolicyContextException {<br /> TestPolicyConfigurationStateMachine testPolicyConfigurationStateMachine = configurators.get(contextID);<br /> if (testPolicyConfigurationStateMachine == null) {<br /> return false;<br /> }<br /> <br /> return testPolicyConfigurationStateMachine.inService();<br /> }<br /> <br /> public static TestPolicyConfiguration getCurrentPolicyConfiguration() {<br /> return (TestPolicyConfiguration) configurators.get(getContextID()).getPolicyConfiguration();<br /> }<br /> <br />}<br /></pre></div> <p><h4>A state machine that controls the life-cyle of this permission collector </h4><p> The state machine as required by the spec was left out in the previous example, but we've implemented it now. A possible implementation could have been to actually use a generic state machine that's been given some kind of rules file. Indeed, some implementations take this approach. But as the rules are actually not that complicated and there are not much transitions to speak of I found that just providing a few checks was a much easier method. <p>A class such as this would perhaps better be provided by the container, as it seems unlikely individual PolicyConfigurations would often if ever need to do anything specific here. <div style="font-size:90%;"><pre class="brush: java;"><br />import static test.TestPolicyConfigurationStateMachine.State.DELETED;<br />import static test.TestPolicyConfigurationStateMachine.State.INSERVICE;<br />import static test.TestPolicyConfigurationStateMachine.State.OPEN;<br /><br />import java.security.Permission;<br />import java.security.PermissionCollection;<br /><br />import javax.security.jacc.PolicyConfiguration;<br />import javax.security.jacc.PolicyConfigurationFactory;<br />import javax.security.jacc.PolicyContextException;<br /><br />public class TestPolicyConfigurationStateMachine implements PolicyConfiguration {<br /><br /> public static enum State {<br /> OPEN, INSERVICE, DELETED<br /> };<br /><br /> private State state = OPEN;<br /> private PolicyConfiguration policyConfiguration;<br /> <br /><br /> public TestPolicyConfigurationStateMachine(PolicyConfiguration policyConfiguration) {<br /> this.policyConfiguration = policyConfiguration;<br /> }<br /> <br /> public PolicyConfiguration getPolicyConfiguration() {<br /> return policyConfiguration;<br /> }<br /><br /> <br /> // ### Methods that can be called in any state and don't change state<br /> <br /> @Override<br /> public String getContextID() throws PolicyContextException {<br /> return policyConfiguration.getContextID();<br /> }<br /> <br /> @Override<br /> public boolean inService() throws PolicyContextException {<br /> return state == INSERVICE;<br /> }<br /> <br /> <br /> // ### Methods where state should be OPEN and don't change state<br /> <br /> @Override<br /> public void addToExcludedPolicy(Permission permission) throws PolicyContextException {<br /> checkStateIs(OPEN);<br /> policyConfiguration.addToExcludedPolicy(permission);<br /> }<br /><br /> @Override<br /> public void addToUncheckedPolicy(Permission permission) throws PolicyContextException {<br /> checkStateIs(OPEN);<br /> policyConfiguration.addToUncheckedPolicy(permission);<br /> }<br /><br /> @Override<br /> public void addToRole(String roleName, Permission permission) throws PolicyContextException {<br /> checkStateIs(OPEN);<br /> policyConfiguration.addToRole(roleName, permission);<br /> }<br /> <br /> @Override<br /> public void addToExcludedPolicy(PermissionCollection permissions) throws PolicyContextException {<br /> checkStateIs(OPEN);<br /> policyConfiguration.addToExcludedPolicy(permissions);<br /> }<br /> <br /> @Override<br /> public void addToUncheckedPolicy(PermissionCollection permissions) throws PolicyContextException {<br /> checkStateIs(OPEN);<br /> policyConfiguration.addToUncheckedPolicy(permissions);<br /> }<br /> <br /> @Override<br /> public void addToRole(String roleName, PermissionCollection permissions) throws PolicyContextException {<br /> checkStateIs(OPEN);<br /> policyConfiguration.addToRole(roleName, permissions);<br /> }<br /> <br /> @Override<br /> public void linkConfiguration(PolicyConfiguration link) throws PolicyContextException {<br /> checkStateIs(OPEN);<br /> policyConfiguration.linkConfiguration(link);<br /> }<br /> <br /> @Override<br /> public void removeExcludedPolicy() throws PolicyContextException {<br /> checkStateIs(OPEN);<br /> policyConfiguration.removeExcludedPolicy();<br /> <br /> }<br /><br /> @Override<br /> public void removeRole(String roleName) throws PolicyContextException {<br /> checkStateIs(OPEN);<br /> policyConfiguration.removeRole(roleName);<br /> }<br /><br /> @Override<br /> public void removeUncheckedPolicy() throws PolicyContextException {<br /> checkStateIs(OPEN);<br /> policyConfiguration.removeUncheckedPolicy();<br /> }<br /> <br /> <br /> // Methods that change the state<br /> //<br /> // commit() can only be called when the state is OPEN or INSERVICE and next state is always INSERVICE<br /> // delete() can always be called and target state will always be DELETED<br /> // open() can always be called and target state will always be OPEN<br /> <br /> @Override<br /> public void commit() throws PolicyContextException {<br /> checkStateIsNot(DELETED);<br /> <br /> if (state == OPEN) {<br /> // Not 100% sure; allow double commit, or ignore double commit?<br /> // Here we ignore and only call commit on the actual policyConfiguration<br /> // when the state is OPEN<br /> policyConfiguration.commit();<br /> state = INSERVICE;<br /> }<br /> }<br /><br /> @Override<br /> public void delete() throws PolicyContextException {<br /> policyConfiguration.delete();<br /> state = DELETED;<br /> }<br /> <br /> /**<br /> * Transition back to open. This method is required because of the {@link PolicyConfigurationFactory} contract, but is<br /> * mysteriously missing from the interface.<br /> */<br /> public void open() {<br /> state = OPEN;<br /> }<br /> <br /> <br /> // ### Private methods<br /> <br /> private void checkStateIs(State requiredState) {<br /> if (state != requiredState) {<br /> throw new IllegalStateException("Required status is " + requiredState + " but actual state is " + state);<br /> }<br /> }<br /> <br /> private void checkStateIsNot(State undesiredState) {<br /> if (state == undesiredState) {<br /> throw new IllegalStateException("State could not be " + undesiredState + " but actual state is");<br /> }<br /> }<br /><br />}<br /></pre></div> <p><h4> Linking permissions of multiple modules and utilities </h4><p> As mentioned we did not implement linking (perhaps we'll look at this in a future article), but as its an interface method we have to put an (empty) implementation somewhere. At the same time JACC curiously requires us to implement a couple of variations on the permission collection methods that don't even seem to be called in practice by any container we looked at. Finally the <i>PolicyConfiguration</i> interface requires an explicit life-cycle method and an identity method. The life-cycle method is not implemented either since all life-cycle managing is done by the state machine that wraps our actual <i>PolicyConfiguration</i>. <p>All these "distracting" methods were conveniently shoved into a base class as follows: <div style="font-size:90%;"><pre class="brush: java;"><br />import static java.util.Collections.list;<br /><br />import java.security.Permission;<br />import java.security.PermissionCollection;<br /><br />import javax.security.jacc.PolicyConfiguration;<br />import javax.security.jacc.PolicyContextException;<br /><br />public abstract class TestPolicyConfigurationBase implements PolicyConfiguration {<br /> <br /> private final String contextID;<br /> <br /> public TestPolicyConfigurationBase(String contextID) {<br /> this.contextID = contextID;<br /> }<br /> <br /> @Override<br /> public String getContextID() throws PolicyContextException {<br /> return contextID;<br /> }<br /> <br /> @Override<br /> public void addToExcludedPolicy(PermissionCollection permissions) throws PolicyContextException {<br /> for (Permission permission : list(permissions.elements())) {<br /> addToExcludedPolicy(permission);<br /> }<br /> }<br /> <br /> @Override<br /> public void addToUncheckedPolicy(PermissionCollection permissions) throws PolicyContextException {<br /> for (Permission permission : list(permissions.elements())) {<br /> addToUncheckedPolicy(permission);<br /> }<br /> }<br /> <br /> @Override<br /> public void addToRole(String roleName, PermissionCollection permissions) throws PolicyContextException {<br /> for (Permission permission : list(permissions.elements())) {<br /> addToRole(roleName, permission);<br /> }<br /> }<br /><br /> @Override<br /> public void linkConfiguration(PolicyConfiguration link) throws PolicyContextException {<br /> }<br /> <br /> @Override<br /> public boolean inService() throws PolicyContextException {<br /> // Not used, taken care of by PolicyConfigurationStateMachine<br /> return true;<br /> }<br /><br />}<br /></pre></div> <p><h4> Collecting and managing permissions </h4><p> The next step concerns a base class for a <i>PolicyConfiguration</i> that takes care of the actual collection of permissions, and making those collected permissions available later on. For each permission that the container discovers it calls the appropriate method in this class. <p>This kind of permission collecting, like the state machine, is actually pretty generic. One wonders if it wouldn't be a great deal simpler if the container just called a single <i>init()</i> method once (or even better, used injection) with a simple data structure containing collections of all permission types. Looking at some container implementations it indeed looks like the container has those collections already and just loops over them handing them one by one to our <i>PolicyConfiguration</i>. <div style="font-size:90%;"><pre class="brush: java;"><br />import java.security.Permission;<br />import java.security.Permissions;<br />import java.util.HashMap;<br />import java.util.Map;<br /><br />import javax.security.jacc.PolicyContextException;<br /><br />public abstract class TestPolicyConfigurationPermissions extends TestPolicyConfigurationBase {<br /><br /> private Permissions excludedPermissions = new Permissions();<br /> private Permissions uncheckedPermissions = new Permissions();<br /> private Map&lt;String, Permissions&gt; perRolePermissions = new HashMap&lt;String, Permissions&gt;();<br /> <br /> public TestPolicyConfigurationPermissions(String contextID) {<br /> super(contextID);<br /> }<br /><br /> @Override<br /> public void addToExcludedPolicy(Permission permission) throws PolicyContextException {<br /> excludedPermissions.add(permission);<br /> }<br /><br /> @Override<br /> public void addToUncheckedPolicy(Permission permission) throws PolicyContextException {<br /> uncheckedPermissions.add(permission);<br /> }<br /><br /> @Override<br /> public void addToRole(String roleName, Permission permission) throws PolicyContextException {<br /> Permissions permissions = perRolePermissions.get(roleName);<br /> if (permissions == null) {<br /> permissions = new Permissions();<br /> perRolePermissions.put(roleName, permissions);<br /> }<br /> <br /> permissions.add(permission);<br /> }<br /> <br /> @Override<br /> public void delete() throws PolicyContextException {<br /> removeExcludedPolicy();<br /> removeUncheckedPolicy();<br /> perRolePermissions.clear();<br /> }<br /><br /> @Override<br /> public void removeExcludedPolicy() throws PolicyContextException {<br /> excludedPermissions = new Permissions();<br /> }<br /><br /> @Override<br /> public void removeRole(String roleName) throws PolicyContextException {<br /> if (perRolePermissions.containsKey(roleName)) {<br /> perRolePermissions.remove(roleName);<br /> } else if ("*".equals(roleName)) {<br /> perRolePermissions.clear();<br /> }<br /> }<br /><br /> @Override<br /> public void removeUncheckedPolicy() throws PolicyContextException {<br /> uncheckedPermissions = new Permissions();<br /> }<br /> <br /> public Permissions getExcludedPermissions() {<br /> return excludedPermissions;<br /> }<br /><br /> public Permissions getUncheckedPermissions() {<br /> return uncheckedPermissions;<br /> }<br /><br /> public Map&lt;String, Permissions&gt; getPerRolePermissions() {<br /> return perRolePermissions;<br /> }<br /><br />}<br /></pre></div> <p><h4> Processing permissions after collecting </h4><p> The final part of the <i>PolicyConfiguration</i> concerns a kind of life cycle method again, namely a method that the container calls to indicate all permissions have been handed over to the <i>PolicyConfiguration</i>. In a more modern implementation this might have been an <i>@PostConstruct</i> annotated method. <p>Contrary to most methods of the <i>PolicyConfiguration</i> that we've seen until now, what happens here is pretty specific to the custom policy provider. Some implementations do a lot of work here and generate a .policy file in the standard Java SE format and write that to disk. This file is then intended to be read back by a standard Java SE Policy implementation. <p>Other implementations use this moment to optimize the collected permissions by transforming them into their own internal data structure. <p>In our case we keep the permissions as we collected them and just instantiate a role mapper implementation at this point. The full set of roles that are associated with permissions that each depend on a certain role are passed into the role mapper. <div style="font-size:90%;"><pre class="brush: java;"><br />import javax.security.jacc.PolicyContextException;<br /><br />public class TestPolicyConfiguration extends TestPolicyConfigurationPermissions {<br /><br /> public TestPolicyConfiguration(String contextID) {<br /> super(contextID);<br /> }<br /> <br /> private TestRoleMapper roleMapper;<br /><br /> @Override<br /> public void commit() throws PolicyContextException {<br /> roleMapper = new TestRoleMapper(getContextID(), getPerRolePermissions().keySet());<br /> }<br /> <br /> public TestRoleMapper getRoleMapper() {<br /> return roleMapper;<br /> }<br /><br />}<br /></pre></div> The role mapper referenced in the code shown above was presented in part II of this article and didn't change between parts, but for completeness we'll present it here again: <div style="font-size:70%;"><pre class="brush: java;"><br />import static java.util.Arrays.asList;<br />import static java.util.Collections.list;<br /><br />import java.lang.reflect.InvocationHandler;<br />import java.lang.reflect.InvocationTargetException;<br />import java.lang.reflect.Method;<br />import java.lang.reflect.Proxy;<br />import java.security.Principal;<br />import java.security.acl.Group;<br />import java.util.ArrayList;<br />import java.util.Collection;<br />import java.util.HashMap;<br />import java.util.List;<br />import java.util.Map;<br />import java.util.Set;<br />import java.util.concurrent.ConcurrentHashMap;<br />import java.util.concurrent.ConcurrentMap;<br /><br />import javax.security.auth.Subject;<br /><br />public class TestRoleMapper {<br /> <br /> private static Object geronimoPolicyConfigurationFactoryInstance;<br /> private static ConcurrentMap&lt;String, Map&lt;Principal, Set&lt;String&gt;&gt;&gt; geronimoContextToRoleMapping;<br /> <br /> private Map&lt;String, List&lt;String&gt;&gt; groupToRoles = new HashMap&lt;&gt;();<br /><br /> private boolean oneToOneMapping;<br /> private boolean anyAuthenticatedUserRoleMapped = false;<br /> <br /> public static void onFactoryCreated() {<br /> tryInitGeronimo();<br /> }<br /> <br /> private static void tryInitGeronimo() {<br /> try {<br /> // Geronimo 3.0.1 contains a protection mechanism to ensure only a Geronimo policy provider is installed.<br /> // This protection can be beat by creating an instance of GeronimoPolicyConfigurationFactory once. This instance<br /> // will statically register itself with an internal Geronimo class<br /> geronimoPolicyConfigurationFactoryInstance = Class.forName("org.apache.geronimo.security.jacc.mappingprovider.GeronimoPolicyConfigurationFactory").newInstance();<br /> geronimoContextToRoleMapping = new ConcurrentHashMap&lt;&gt;();<br /> } catch (Exception e) {<br /> // ignore<br /> }<br /> }<br /> <br /> public static void onPolicyConfigurationCreated(final String contextID) {<br /> <br /> // Are we dealing with Geronimo?<br /> if (geronimoPolicyConfigurationFactoryInstance != null) {<br /> <br /> // PrincipalRoleConfiguration<br /> <br /> try {<br /> Class&lt;?&gt; geronimoPolicyConfigurationClass = Class.forName("org.apache.geronimo.security.jacc.mappingprovider.GeronimoPolicyConfiguration");<br /> <br /> Object geronimoPolicyConfigurationProxy = Proxy.newProxyInstance(TestRoleMapper.class.getClassLoader(), new Class[] {geronimoPolicyConfigurationClass}, new InvocationHandler() {<br /> <br /> @SuppressWarnings("unchecked")<br /> @Override<br /> public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {<br /><br /> // Take special action on the following method:<br /> <br /> // void setPrincipalRoleMapping(Map&lt;Principal, Set&lt;String&gt;&gt; principalRoleMap) throws PolicyContextException;<br /> if (method.getName().equals("setPrincipalRoleMapping")) {<br /> <br /> geronimoContextToRoleMapping.put(contextID, (Map&lt;Principal, Set&lt;String&gt;&gt;) args[0]);<br /> <br /> }<br /> return null;<br /> }<br /> });<br /> <br /> // Set the proxy on the GeronimoPolicyConfigurationFactory so it will call us back later with the role mapping via the following method:<br /> <br /> // public void setPolicyConfiguration(String contextID, GeronimoPolicyConfiguration configuration) {<br /> Class.forName("org.apache.geronimo.security.jacc.mappingprovider.GeronimoPolicyConfigurationFactory")<br /> .getMethod("setPolicyConfiguration", String.class, geronimoPolicyConfigurationClass)<br /> .invoke(geronimoPolicyConfigurationFactoryInstance, contextID, geronimoPolicyConfigurationProxy);<br /> <br /> <br /> } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {<br /> // Ignore<br /> }<br /> }<br /> }<br /> <br /><br /> public TestRoleMapper(String contextID, Collection&lt;String&gt; allDeclaredRoles) {<br /> // Initialize the groupToRoles map<br /><br /> // Try to get a hold of the proprietary role mapper of each known<br /> // AS. Sad that this is needed :(<br /> if (tryGlassFish(contextID, allDeclaredRoles)) {<br /> return;<br /> } else if (tryWebLogic(contextID, allDeclaredRoles)) {<br /> return;<br /> } else if (tryGeronimo(contextID, allDeclaredRoles)) {<br /> return;<br /> } else {<br /> oneToOneMapping = true;<br /> }<br /> }<br /><br /> public List&lt;String&gt; getMappedRolesFromPrincipals(Principal[] principals) {<br /> return getMappedRolesFromPrincipals(asList(principals));<br /> }<br /><br /> public boolean isAnyAuthenticatedUserRoleMapped() {<br /> return anyAuthenticatedUserRoleMapped;<br /> }<br /><br /> public List&lt;String&gt; getMappedRolesFromPrincipals(Iterable&lt;Principal&gt; principals) {<br /><br /> // Extract the list of groups from the principals. These principals typically contain<br /> // different kind of principals, some groups, some others. The groups are unfortunately vendor<br /> // specific.<br /> List&lt;String&gt; groups = getGroupsFromPrincipals(principals);<br /><br /> // Map the groups to roles. E.g. map "admin" to "administrator". Some servers require this.<br /> return mapGroupsToRoles(groups);<br /> }<br /><br /> private List&lt;String&gt; mapGroupsToRoles(List&lt;String&gt; groups) {<br /><br /> if (oneToOneMapping) {<br /> // There is no mapping used, groups directly represent roles.<br /> return groups;<br /> }<br /><br /> List&lt;String&gt; roles = new ArrayList&lt;&gt;();<br /><br /> for (String group : groups) {<br /> if (groupToRoles.containsKey(group)) {<br /> roles.addAll(groupToRoles.get(group));<br /> }<br /> }<br /><br /> return roles;<br /> }<br /><br /> private boolean tryGlassFish(String contextID, Collection&lt;String&gt; allDeclaredRoles) {<br /><br /> try {<br /> Class&lt;?&gt; SecurityRoleMapperFactoryClass = Class.forName("org.glassfish.deployment.common.SecurityRoleMapperFactory");<br /><br /> Object factoryInstance = Class.forName("org.glassfish.internal.api.Globals")<br /> .getMethod("get", SecurityRoleMapperFactoryClass.getClass())<br /> .invoke(null, SecurityRoleMapperFactoryClass);<br /><br /> Object securityRoleMapperInstance = SecurityRoleMapperFactoryClass.getMethod("getRoleMapper", String.class)<br /> .invoke(factoryInstance, contextID);<br /><br /> @SuppressWarnings("unchecked")<br /> Map&lt;String, Subject&gt; roleToSubjectMap = (Map&lt;String, Subject&gt;) Class.forName("org.glassfish.deployment.common.SecurityRoleMapper")<br /> .getMethod("getRoleToSubjectMapping")<br /> .invoke(securityRoleMapperInstance);<br /><br /> for (String role : allDeclaredRoles) {<br /> if (roleToSubjectMap.containsKey(role)) {<br /> Set&lt;Principal&gt; principals = roleToSubjectMap.get(role).getPrincipals();<br /><br /> List&lt;String&gt; groups = getGroupsFromPrincipals(principals);<br /> for (String group : groups) {<br /> if (!groupToRoles.containsKey(group)) {<br /> groupToRoles.put(group, new ArrayList&lt;String&gt;());<br /> }<br /> groupToRoles.get(group).add(role);<br /> }<br /><br /> if ("**".equals(role) && !groups.isEmpty()) {<br /> // JACC spec 3.2 states:<br /> //<br /> // "For the any "authenticated user role", "**", and unless an application specific mapping has<br /> // been established for this role,<br /> // the provider must ensure that all permissions added to the role are granted to any<br /> // authenticated user."<br /> //<br /> // Here we check for the "unless" part mentioned above. If we're dealing with the "**" role here<br /> // and groups is not<br /> // empty, then there's an application specific mapping and "**" maps only to those groups, not<br /> // to any authenticated user.<br /> anyAuthenticatedUserRoleMapped = true;<br /> }<br /> }<br /> }<br /><br /> return true;<br /><br /> } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException<br /> | InvocationTargetException e) {<br /> return false;<br /> }<br /> }<br /><br /> private boolean tryWebLogic(String contextID, Collection&lt;String&gt; allDeclaredRoles) {<br /><br /> try {<br /><br /> // See http://docs.oracle.com/cd/E21764_01/apirefs.1111/e13941/weblogic/security/jacc/RoleMapperFactory.html<br /> Class&lt;?&gt; roleMapperFactoryClass = Class.forName("weblogic.security.jacc.RoleMapperFactory");<br /><br /> // RoleMapperFactory implementation class always seems to be the value of what is passed on the commandline<br /> // via the -Dweblogic.security.jacc.RoleMapperFactory.provider option.<br /> // See http://docs.oracle.com/cd/E57014_01/wls/SCPRG/server_prot.htm<br /> Object roleMapperFactoryInstance = roleMapperFactoryClass.getMethod("getRoleMapperFactory")<br /> .invoke(null);<br /><br /> // See http://docs.oracle.com/cd/E21764_01/apirefs.1111/e13941/weblogic/security/jacc/RoleMapperFactory.html#getRoleMapperForContextID(java.lang.String)<br /> Object roleMapperInstance = roleMapperFactoryClass.getMethod("getRoleMapperForContextID", String.class)<br /> .invoke(roleMapperFactoryInstance, contextID);<br /><br /> // This seems really awkward; the Map contains BOTH group names and user names, without ANY way to<br /> // distinguish between the two.<br /> // If a user now has a name that happens to be a role as well, we have an issue :X<br /> @SuppressWarnings("unchecked")<br /> Map&lt;String, String[]&gt; roleToPrincipalNamesMap = (Map&lt;String, String[]&gt;) Class.forName("weblogic.security.jacc.simpleprovider.RoleMapperImpl")<br /> .getMethod("getRolesToPrincipalNames")<br /> .invoke(roleMapperInstance);<br /><br /> for (String role : allDeclaredRoles) {<br /> if (roleToPrincipalNamesMap.containsKey(role)) {<br /><br /> List&lt;String&gt; groupsOrUserNames = asList(roleToPrincipalNamesMap.get(role));<br /><br /> for (String groupOrUserName : roleToPrincipalNamesMap.get(role)) {<br /> // Ignore the fact that the collection also contains user names and hope<br /> // that there are no user names in the application with the same name as a group<br /> if (!groupToRoles.containsKey(groupOrUserName)) {<br /> groupToRoles.put(groupOrUserName, new ArrayList&lt;String&gt;());<br /> }<br /> groupToRoles.get(groupOrUserName).add(role);<br /> }<br /><br /> if ("**".equals(role) && !groupsOrUserNames.isEmpty()) {<br /> // JACC spec 3.2 states: [...]<br /> anyAuthenticatedUserRoleMapped = true;<br /> }<br /> }<br /> }<br /><br /> return true;<br /><br /> } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException<br /> | InvocationTargetException e) {<br /> return false;<br /> }<br /> }<br /> <br /> private boolean tryGeronimo(String contextID, Collection&lt;String&gt; allDeclaredRoles) {<br /> if (geronimoContextToRoleMapping != null) {<br /> <br /> if (geronimoContextToRoleMapping.containsKey(contextID)) {<br /> Map&lt;Principal, Set&lt;String&gt;&gt; principalsToRoles = geronimoContextToRoleMapping.get(contextID);<br /> <br /> for (Map.Entry&lt;Principal, Set&lt;String&gt;&gt; entry : principalsToRoles.entrySet()) {<br /> <br /> // Convert the principal that's used as the key in the Map to a list of zero or more groups.<br /> // (for Geronimo we know that using the default role mapper it's always zero or one group)<br /> for (String group : principalToGroups(entry.getKey())) {<br /> if (!groupToRoles.containsKey(group)) {<br /> groupToRoles.put(group, new ArrayList&lt;String&gt;());<br /> }<br /> groupToRoles.get(group).addAll(entry.getValue());<br /> <br /> if (entry.getValue().contains("**")) {<br /> // JACC spec 3.2 states: [...]<br /> anyAuthenticatedUserRoleMapped = true;<br /> }<br /> }<br /> }<br /> }<br /> <br /> return true;<br /> }<br /> <br /> return false;<br /> }<br /><br /> /**<br /> * Extracts the roles from the vendor specific principals. SAD that this is needed :(<br /> * <br /> * @param principals<br /> * @return<br /> */<br /> public List&lt;String&gt; getGroupsFromPrincipals(Iterable&lt;Principal&gt; principals) {<br /> List&lt;String&gt; groups = new ArrayList&lt;&gt;();<br /><br /> for (Principal principal : principals) {<br /> if (principalToGroups(principal, groups)) {<br /> // return value of true means we're done early. This can be used<br /> // when we know there's only 1 principal holding all the groups<br /> return groups;<br /> }<br /> }<br /><br /> return groups;<br /> }<br /> <br /> public List&lt;String&gt; principalToGroups(Principal principal) {<br /> List&lt;String&gt; groups = new ArrayList&lt;&gt;();<br /> principalToGroups(principal, groups);<br /> return groups;<br /> }<br /> <br /> public boolean principalToGroups(Principal principal, List&lt;String&gt; groups) {<br /> switch (principal.getClass().getName()) {<br /><br /> case "org.glassfish.security.common.Group": // GlassFish<br /> case "org.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal": // Geronimo<br /> case "weblogic.security.principal.WLSGroupImpl": // WebLogic<br /> case "jeus.security.resource.GroupPrincipalImpl": // JEUS<br /> groups.add(principal.getName());<br /> break;<br /> <br /> case "org.jboss.security.SimpleGroup": // JBoss<br /> if (principal.getName().equals("Roles") && principal instanceof Group) {<br /> Group rolesGroup = (Group) principal;<br /> for (Principal groupPrincipal : list(rolesGroup.members())) {<br /> groups.add(groupPrincipal.getName());<br /> }<br /> <br /> // Should only be one group holding the roles, so can exit the loop<br /> // early<br /> return true;<br /> }<br /> }<br /> return false;<br /> }<br /><br />}<br /></pre></div> <p><h4> An "authorization module" using permissions for authorization decisions </h4><p> At long last we present the actual "authorization module" (called Policy in Java SE and JACC). Compared to the version we presented <a href="http://arjan-tijms.omnifaces.org/2014/03/implementing-container-authorization-in.html">before</a> this now delegates extracting the list of roles from the principles that are associated with the authenticated user to the role mapper we showed above. In addition to that we also added the case where we check for the so-called "any authenticated user", which means it doesn't matter which roles a user has, but only the fact if this user is authenticated or not counts. <p>This authorization module implements the default authorization algorithm defined by the Servlet and JACC specs, which does the following checks in order: <ol><li> Is permission excluded? (nobody can access those) <li> Is permission unchecked? (everyone can access those) <li> Is permission granted to every authenticated user? <li> Is permission granted to any of the roles the current user is in? <li> Is permission granted by the previous (if any) authorization module? </ol> <p>The idea of a custom authorization module is often to do something specific authorization wise, so this would be the most likely place to put custom code. In fact, if only this particular class could be injected with the permissions that now have to be collected by our own classes as shown above, then JACC would be massively simplified in one fell swoop. <p>In that case only this class would be have to be implemented. Even better would be if the default algorithm was also provided in a portable way. With that we could potentially only implement the parts that are really different for our custom implementation and leave the rest to the default implementation. <div style="font-size:90%;"><pre class="brush: java;"><br />import static java.util.Arrays.asList;<br />import static java.util.Collections.list;<br />import static test.TestPolicyConfigurationFactory.getCurrentPolicyConfiguration;<br /><br />import java.security.CodeSource;<br />import java.security.Permission;<br />import java.security.PermissionCollection;<br />import java.security.Permissions;<br />import java.security.Policy;<br />import java.security.Principal;<br />import java.security.ProtectionDomain;<br />import java.util.List;<br />import java.util.Map;<br /><br />public class TestPolicy extends Policy {<br /> <br /> private Policy previousPolicy = Policy.getPolicy();<br /> <br /> @Override<br /> public boolean implies(ProtectionDomain domain, Permission permission) {<br /> <br /> TestPolicyConfiguration policyConfiguration = getCurrentPolicyConfiguration();<br /> TestRoleMapper roleMapper = policyConfiguration.getRoleMapper();<br /> <br /> if (isExcluded(policyConfiguration.getExcludedPermissions(), permission)) {<br /> // Excluded permissions cannot be accessed by anyone<br /> return false;<br /> }<br /> <br /> if (isUnchecked(policyConfiguration.getUncheckedPermissions(), permission)) {<br /> // Unchecked permissions are free to be accessed by everyone<br /> return true;<br /> }<br /> <br /> List&lt;Principal&gt; currentUserPrincipals = asList(domain.getPrincipals());<br /> <br /> if (!roleMapper.isAnyAuthenticatedUserRoleMapped() && !currentUserPrincipals.isEmpty()) {<br /> // The "any authenticated user" role is not mapped, so available to anyone and the current<br /> // user is assumed to be authenticated (we assume that an unauthenticated user doesn't have any principals<br /> // whatever they are)<br /> if (hasAccessViaRole(policyConfiguration.getPerRolePermissions(), "**", permission)) {<br /> // Access is granted purely based on the user being authenticated (the actual roles, if any, the user has it not important)<br /> return true;<br /> }<br /> }<br /> <br /> if (hasAccessViaRoles(policyConfiguration.getPerRolePermissions(), roleMapper.getMappedRolesFromPrincipals(currentUserPrincipals), permission)) {<br /> // Access is granted via role. Note that if this returns false it doesn't mean the permission is not<br /> // granted. A role can only grant, not take away permissions.<br /> return true;<br /> }<br /> <br /> // Access not granted via any of the JACC maintained Permissions. Check the previous (default) policy.<br /> // Note: this is likely to be called in case it concerns a Java SE type permissions.<br /> // TODO: Should we not distinguish between JACC and Java SE Permissions at the start of this method? Seems<br /> // very unlikely that JACC would ever say anything about a Java SE Permission, or that the Java SE<br /> // policy says anything about a JACC Permission. Why are these two systems even combined in the first place?<br /> if (previousPolicy != null) {<br /> return previousPolicy.implies(domain, permission);<br /> }<br /> <br /> return false;<br /> }<br /><br /> @Override<br /> public PermissionCollection getPermissions(ProtectionDomain domain) {<br /><br /> Permissions permissions = new Permissions();<br /> <br /> TestPolicyConfiguration policyConfiguration = getCurrentPolicyConfiguration();<br /> TestRoleMapper roleMapper = policyConfiguration.getRoleMapper();<br /> <br /> Permissions excludedPermissions = policyConfiguration.getExcludedPermissions();<br /><br /> // First get all permissions from the previous (original) policy<br /> if (previousPolicy != null) {<br /> collectPermissions(previousPolicy.getPermissions(domain), permissions, excludedPermissions);<br /> }<br /><br /> // If there are any static permissions, add those next<br /> if (domain.getPermissions() != null) {<br /> collectPermissions(domain.getPermissions(), permissions, excludedPermissions);<br /> }<br /><br /> // Thirdly, get all unchecked permissions<br /> collectPermissions(policyConfiguration.getUncheckedPermissions(), permissions, excludedPermissions);<br /><br /> // Finally get the permissions for each role *that the current user has*<br /> //<br /> // Note that the principles that are put into the ProtectionDomain object are those from the current user.<br /> // (for a Server application, passing in a Subject would have been more logical, but the Policy class was<br /> // made for Java SE with code-level security in mind)<br /> Map&lt;String, Permissions&gt; perRolePermissions = policyConfiguration.getPerRolePermissions();<br /> for (String role : roleMapper.getMappedRolesFromPrincipals(domain.getPrincipals())) {<br /> if (perRolePermissions.containsKey(role)) {<br /> collectPermissions(perRolePermissions.get(role), permissions, excludedPermissions);<br /> }<br /> }<br /><br /> return permissions;<br /> }<br /> <br /> @Override<br /> public PermissionCollection getPermissions(CodeSource codesource) {<br /><br /> Permissions permissions = new Permissions();<br /> <br /> TestPolicyConfigurationPermissions policyConfiguration = getCurrentPolicyConfiguration();<br /> Permissions excludedPermissions = policyConfiguration.getExcludedPermissions();<br /><br /> // First get all permissions from the previous (original) policy<br /> if (previousPolicy != null) {<br /> collectPermissions(previousPolicy.getPermissions(codesource), permissions, excludedPermissions);<br /> }<br /><br /> // Secondly get the static permissions. Note that there are only two sources possible here, without<br /> // knowing the roles of the current user we can't check the per role permissions.<br /> collectPermissions(policyConfiguration.getUncheckedPermissions(), permissions, excludedPermissions);<br /><br /> return permissions;<br /> }<br /> <br /> private boolean isExcluded(Permissions excludedPermissions, Permission permission) {<br /> if (excludedPermissions.implies(permission)) {<br /> return true;<br /> }<br /> <br /> for (Permission excludedPermission : list(excludedPermissions.elements())) {<br /> if (permission.implies(excludedPermission)) {<br /> return true;<br /> }<br /> }<br /> <br /> return false;<br /> }<br /> <br /> private boolean isUnchecked(Permissions uncheckedPermissions, Permission permission) {<br /> return uncheckedPermissions.implies(permission);<br /> }<br /> <br /> private boolean hasAccessViaRoles(Map&lt;String, Permissions&gt; perRolePermissions, List&lt;String&gt; roles, Permission permission) {<br /> for (String role : roles) {<br /> if (hasAccessViaRole(perRolePermissions, role, permission)) {<br /> return true;<br /> }<br /> }<br /> <br /> return false;<br /> }<br /> <br /> private boolean hasAccessViaRole(Map&lt;String, Permissions&gt; perRolePermissions, String role, Permission permission) {<br /> return perRolePermissions.containsKey(role) && perRolePermissions.get(role).implies(permission);<br /> }<br /> <br /> /**<br /> * Copies permissions from a source into a target skipping any permission that's excluded.<br /> * <br /> * @param sourcePermissions<br /> * @param targetPermissions<br /> * @param excludedPermissions<br /> */<br /> private void collectPermissions(PermissionCollection sourcePermissions, PermissionCollection targetPermissions, Permissions excludedPermissions) {<br /> <br /> boolean hasExcludedPermissions = excludedPermissions.elements().hasMoreElements();<br /> <br /> for (Permission permission : list(sourcePermissions.elements())) {<br /> if (!hasExcludedPermissions || !isExcluded(excludedPermissions, permission)) {<br /> targetPermissions.add(permission);<br /> }<br /> }<br /> }<br /> <br />}<br /></pre></div> <p><h3> Conclusion </h3><p> This concludes our three parter on revisiting JACC. In this third and final part we have looked at an actual Policy Provider. We have broken up the implementation into several parts that each focused on a particular responsibility. While the Policy Provider is complete and working (tested on GlassFish, WebLogic and Geronimo) we did not implement module linking yet, so it's with the caveat that it only works within a single war. <p>To implement another custom Policy Provider many of these parts can probably be re-used as-is and likely only the Policy itself has to customized. <p><i>Arjan Tijms</i> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com0tag:blogger.com,1999:blog-4498889353428710313.post-28000659607376088042015-03-11T17:08:00.000-07:002015-03-11T17:08:36.118-07:00The most popular Java EE servers in 2014/2015 according to OmniFaces usersFor a little over 3 months (from half of November 2014 to late February 2015) we had a poll on the <a href="http://omnifaces.org">OmniFaces</a> website asking what AS (Application Server) people used with OmniFaces (people could select multiple servers). <p>The response was quite overwhelming for our little project; no less than <b>840 people responded</b>, choosing a grand total of 1108 servers. <p>The final results are as follows: <p><big><table border="1" style="font-size: 110%;"> <tr style="background-color:LightGray;"><th>Position</th> <th>Server</th> <th>Votes (Percentage)</th></tr> <tr><td><b>1</b></td> <td>JBoss (AS/EAP/WildFly)</td> <td>395 (47%)</td></tr> <tr><td><b>2</b></td> <td>GlassFish</td> <td>206 (24%)</td></tr> <tr><td><b>3</b></td> <td>Tomcat/Mojarra/Weld</td> <td>186 (22%)</td></tr> <tr><td><b>4</b></td> <td>TomEE</td> <td>85 (10%)</td></tr> <tr><td><b>5</b></td> <td>WebSphere</td> <td>55 (6%)</td></tr> <tr><td><b>6</b></td> <td>WebLogic</td> <td>49 (6%)</td> </tr> <tr><td><b>7</b></td> <td>Tomcat/MyFaces/OWB</td> <td>33 (3%)</td> </tr> <tr><td><b>8</b></td> <td>Jetty/Mojarra/Weld</td> <td>19 (2%)</td> </tr> <tr><td><b>9</b></td> <td>Geronimo</td> <td>13 (1%) </td> </tr> <tr><td><b>10</b></td> <td>JEUS</td> <td>11 (1%)</td> </tr> <tr><td><b>11</b></td> <td>Liberty</td> <td>9 (1%)</td> </tr> <tr><td><b>12</b></td> <td>Jetty/MyFaces/OWB</td> <td>9 (1%)</td> </tr> <tr><td><b>13</b></td> <td>JOnAS</td> <td>8 (0%)</td> </tr> <tr><td><b>14</b></td> <td>NetWeaver</td> <td>8 (0%)</td> </tr> <tr><td><b>15</b></td> <td>Resin</td> <td>6 (0%)</td> </tr> <tr><td><b>16</b></td> <td>InforSuite</td> <td>5 (0%)</td> </tr> <tr><td><b>17</b></td> <td>WebOTX</td> <td>4 (0%)</td> </tr> <tr><td><b>18</b></td> <td>Interstage AS</td> <td>4 (0%)</td> </tr> <tr><td><b>19</b></td> <td>(u)Cosminexus</td> <td>3 (0%)</td> </tr> </table></big> <p>As can be seen <b>the clear winner here is JBoss</b>, which gets nearly half of all votes and nearly twice the amount of the runner up; GlassFish. Just slightly below GlassFish at number 3 is Tomcat in the specific combination with Mojarra and Weld. <p>It has be noted that Mojarra & Weld are typically but a small part of a homegrown Java EE stack, which often also includes things like Hibernate, Hibernate-Validations and many more components. For the specific case of OmniFaces however the Servlet, JSF and CDI implementations are what matter most so that's why we specifically included these in the poll. Another homegrown stack based on Tomcat, but using Myfaces and OWB (OpenWebBeans) instead scores significantly lower and ends up at place 7. <p>We acknowledge that people not necessarily have to use Mojarra and Weld together, but can also use Mojarra with OWB, or MyFaces with Weld. However we wanted to somewhat limit the options for homegrown stacks, and a little research ahead hinted these were the more popular combinations. In a follow up poll we may zoom into this and specifically address homegrown stacks by asking which individual components people use. <p>An interesting observation is that the entire top 4 consists solely out of open source servers, together good for 103% relative to the amount of people who voted (remember that 1 person could vote for multiple servers), or a total of 79% relative to all servers voted for. <p>While these are certainly impressive numbers, we do have to realize that the voters are self selected and specifically concern those who use OmniFaces. OmniFaces is an open source library without any form of commercial support. It's perhaps not entirely unreasonable to surmise that environments that favor closed source commercially supported servers are less likely to use OmniFaces. Taking that into account, the numbers thus don't necessarily mean that open source servers are indeed used that much in general. <p>That said, the two big commercial servers WebSphere and WebLogic still got a fair amount of votes; 104 together which is 9% relative to all servers voted for. <p>The fully open source and once much talked about server Geronimo got significantly few votes; only 13. The fact that Geronimo has more or less stopped developing its server and the lack of a visible community (people blogging about it, writing articles, responding to issues etc) probably contributes to that. <p>It's somewhat surprising that <a href="http://arjan-tijms.omnifaces.org/2013/06/trying-liberty-855.html">IBM's new lightweight AS Liberty</a> got only 9 votes, where older (and more heavier) AS WebSphere got 55 votes. Maybe Liberty indeed isn't used that much yet, or maybe the name recognition isn't that big at the moment. A potential weakness in the poll is that we left out the company names. For well known servers such as JBoss and GlassFish you rarely see people calling it Red Hat JBoss or Oracle GlassFish, but in case of Liberty it might have been clearer to call it "IBM Liberty (WLP)". <p>Another small surprise is that the <a href="http://arjan-tijms.omnifaces.org/2013/09/diving-into-unknown-jeus-application.html">somewhat obscure server</a> JEUS got as many votes as it did; 11 in total. This is perhaps extra surprising since creator TMaxSoft for some unknown reason consistently calls it a <i>WAS</i> instead of an <i>AS</i>, and the poll asked for the latter. <p>The "<i>Japanese obscure three</i>" (WebOTX, Interstage AS and (u)Cosminexus) are at the bottom of the list, yet at least 3 to 4 persons each claim to be using it with OmniFaces. Since not all of these servers are trivial to obtain, we've never tested OmniFaces on any of them so frankly have no idea how well OmniFaces runs on them. Even though according to this poll it concerns just a small amount of people, we're now quite eager to try out a few of these servers in the future, just to see how things work there. <h3> Conclusion </h3> <p>For the particular community of those who use Omnifaces, we've seen that open source servers in general and particularly JBoss, GlassFish and TomEE are the most popular Java EE servers. Tomcat and Jetty were included as well, but aren't officially Java EE (although one can build stacks on them that get close). <p>A couple of servers, which really are complete Java EE implementations just as well and one might think take just as much work to build and maintain, only see a very low amount of users according to this poll. That's of course not to say that they aren't used much in general, but may just gather to a different audience. <p><i>Arjan Tijms</i> Arjan Tijmshttps://plus.google.com/104480612998561613961noreply@blogger.com1