Saturday, May 26, 2018

[add-on] javax.annotation.security.* with deltaspike

intro/background:
recently DELTASPIKE-1345 was reported. since i checked the available integration of javax.annotation.security.* as well as JSR-375 just recently, it was clear that there isn't a well-established CDI extension which integrates with the servlet- and ejb-api (at least at this point).

in the past few years we usually used @Secured (or @Secures) to integrate with those and other authentication (and authorization) mechanisms. in most cases that allowed a type-safe and more CDI-like approach in combination with solid security-frameworks like http://shiro.apache.org

however, (currently) projects like keycloak are integrated e.g. with wildfly (and therefore with javax.annotation.security.*), but only for servlet based artifacts and EJBs.

since JSR-375 is integrated with CDI out-of-the-box, only EE6 and EE7 still have a gap in view of those annotations for authentication (in combination with CDI). in most cases it's enough to use @Secures in combination with the std. EE-APIs (like it's illustrated for JSF in one of the wildfly-demos). however, it's for sure inconsistent that those annotations can be used with different EE-APIs, but out-of-the-box not with CDI beans. therefore, i prototyped https://github.com/os890/ds-role-bridge-addon
it's a bridge which supports @DenyAll, @PermitAll, @RolesAllowed and @RunAs. i skipped the support for @DeclareRoles in combination with @RunAs, because a full support with EJBs wouldn't be portable anyway. the remaining annotations are also integrated with EJBs and therefore in most cases it should just work as it would be supported out-of-the-box.

the short story:
as shown in the demo-applications it's just needed to add the bridge as a runtime-dependency and use the javax.annotation.security.* annotations directly at the CDI beans. behind the scenes the final-role check is delegated to the servlet-api or if it isn't available (or there is no active servlet-request), a fallback gets triggered which delegates the check to the EJBContext. only @RunAs required a custom role-evaluation (including an explicit approach for the integration with EJBs).

the result:
https://github.com/os890/ds-role-bridge-addon should allow the same overall usage of @DenyAll, @PermitAll, @RolesAllowed and @RunAs (please report an issue if there is a difference). the main (known) difference is that you need to use annotations like @RolesAllowed explicitly (there is no "default/implicit" protection). furthermore, the result of a violation is a java.lang.SecurityException. however, the bridge also provides a rich set of SPIs which allows to customize the default behavior (in this case e.g. with an @Alternative implementation of AccessDeniedHandler).

btw. since cdi is really powerful it took longer to create the examples then the bridge itself.