November 11, 2020
This article demonstrates how to secure Enterprise Java Beans (EJB) using the RolesAllowed annotation. The business logic supporting a RESTful web service is factored out into an EJB. One of the two methods in the EJB is secured while the other is open.
The JavaEE code described this article is on GitHub.
This demonstration uses Basic Authentication to secure access to a protected method of an EJB. The JavaEE RolesAllowed annotation is applied to the method. This means that the authenticated user accessing the EJB must be a member of the specified role. Additionally, another method in the EJB is open to the public. This requires the annotation PermitAll since by default in WildFly, EJB methods are DenyAll.
While the apps I work on enforce access control at the JAX-RS level, EJB security provides additional assurance that developers will not expose restricted business functionality to unauthorized users. EJB security secures technologies besides JAX-RS such as Java Message Service (JMS) or Remoting with a JavaFX application client.
This UML diagram shows the demonstration application. MessageResource is a JAX-RS class that exposes two paths: /public and /protected. /public maps to the MessageResource call "helloWorld". While /protected maps to the MessageResource call "secretMessage".
The JAX-RS calls delegate to the Stateless EJB "MessageBean" using methods of the same name. The EJB helloWorld method is marked with the PermitAll stereotype indicating that an annotation opens access to all callers. The EJB secretMessage method is marked with RolesAllowed. Its annotation is parameterized with "user" which means that only authenticated users with the role "user" can access this method.
@Stateless
public class MessageBean {
@PermitAll
public String helloWorld() { return "Hello, World!"; }
@RolesAllowed("user")
public String secretMessage() { return "A Secret Message"; }
}
EJB security is Role Based Access Control (RBAC) and relies on some other mechanism for a user to establish identity. In this example, the web layer does this with Basic Authentication. The following is the web.xml used in the example. It defines the WildFly Realm "ApplicationRealm" and the BASIC mechanism. This Realm is provded out-of-the-box by WildFly. See here for instructions on working with a PropertiesRealm like ApplicationRealm.
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>ApplicationRealm</realm-name>
</login-config>
</web-app>
Functionally, this solution works however there is a problem in the way that the error is reported. In today's API development, projects like the experiment making API calls early on in the project to get a feel for the services. As things are coded in this example, these developers would not be able to access unauthenticated methods. However, they'd get this error back
javax.ejb.EJBAccessException: WFLYEJB0364: Invocation on method: public java.lang.String us.bekwam.security.examples.ejb.MessageBean.secretMessage() of bean: MessageBean is not allowed
rather than a standard 401 Unauthorized since the EJB level exception maps to a JAX-RS 500 Internal Server Error. You can map exceptions in JAX-RS with special handlers, but I find working with url-patterns at the web layer better because I often use Servlet Filters for additional security requirements.
If you'd like to see a friendlier web-oriented example using similar code, check out WildFly Basic Auth.
Building security in layers is important. While someone granting access to an EJB method is a project insider, annotations can help enforce a misunderstood privilege escalation of protected functions. EJB security is even more useful when EJBs start calling other EJBs with different security requirements. The chain of calls must mesh with the user's role. As the project becomes larger and the relationships more obscured at the coding level, annotations like RolesAllowed are a verification that makes sure everything remains secure.
By Carl Walker
President and Principal Consultant of Bekwam, Inc