9 min read

EJB 3.1 Cookbook

Security is an important aspect of many applications. Central to EJB security is the control of access to classes and methods. There are two approaches to controlling access to EJBs. The first, and the simplest, is through the use of declarative annotations to specify the types of access permitted. The second approach is to use code to control access to the business methods of an EJB. This second approach should not be used unless the declarative approach does not meet the needs of the application. For example, access to a method may be denied during certain times of the day or during certain maintenance periods. Declarative security is not able to handle these types of situations.

In order to incorporate security into an application, it is necessary to understand the Java EE environment and its terminology. The administration of security for the underlying operating system is different from that provided by the EE server. The EE server is concerned with realms, users and groups. The application is largely concerned with roles. The roles need to be mapped to users and groups of a realm for the application to function properly.

A realm is a domain for a server that incorporates security policies. It possesses a set of users and groups which are considered valid users of an application. A user typically corresponds to an individual while a group is a collection of individuals. Group members frequently share a common set of responsibilities. A Java EE server may manage multiple realms.

An application is concerned with roles. Access to EJBs and their methods is determined by the role of a user. Roles are defined in such a manner as to provide a logical way of deciding which users/groups can access which methods. For example, a management type role may have the capability to approve a travel voucher whereas an employee role should not have that capability. By assigning certain users to a role and then specifying which roles can access which methods, we are able to control access to EJBs.

The use of groups makes the process of assigning roles easier. Instead of having to map each individual to a role, the user is assigned to a group and the group is mapped to a role. The business code does not have to check every individual. The Java EE server manages the assignment of users to groups. The application needs only be concerned with controlling a group’s access.

A group is a server level concept. Roles are application level. One group can be associated with multiple applications. For example, a student group may use a student club and student registration application while a faculty group might also use the registration application but with more capability.

A role is simply a name for a set of capabilities. For example, an auditor role may be to review and certify a set of accounts. This role would require read access to many, if not all, of the accounts. However, modification privileges may be restricted. Each application has its own set of roles which have been defined to meet the security needs of the application.

The EE server manages realms consisting of users, groups, and resources. The server will authenticate users using Java’s underlying security features. The user is then referred to as a principal and has a credential containing the user’s security attributes. During the deployment of an application, users and groups are mapped to roles of the application using a deployment descriptor. The configuration of the deployment descriptor is normally the responsibility of the application deployer. During the execution of the application, the Java Authentication and Authorization Service (JAAS) API authenticates a user and creates a principal representing the user. The principal is then passed to an EJB.

Security in a Java EE environment can be viewed from different perspectives. When information is passed between clients and servers, transport level security comes into play. Security at this level can include Secure HTTP (HTTPS) and Secure Sockets Layer (SSL). Messages can be sent across a network in the form of Simple Object Access Protocol (SOAP) messages. These messages can be encrypted. The EE container for EJBs provides application level security which is the focus of the chapter. Most servers provide unified security support between the web container and the EJB container. For example, calls from a servlet in a web container to an EJB are handled automatically resulting in a flexible security mechanism.

Most of the recipes presented in this article are interrelated. If your intention is to try out the code examples, then make sure you cover the first two recipes as they provide the framework for the execution of the other recipes. In the first recipe, Creating the SecurityApplication, we create the foundation application for the remaining recipes. In the second recipe, Configuring the server to handle security, the basic steps needed to configure security for an application are presented.

The use of declarative security is covered in the Controlling security using declarations recipe while programmatic security is discussed in the next article on Controlling security programmatically. The Understanding and declaring roles recipe examines roles in more detail and the Propagating identity recipe talks about how the identity of a user is managed in an application.

Creating the SecurityApplication

In this article, we will create a SecurityApplication built around a simple Voucher entity to persist travel information. This is a simplified version of an application that allows a user to submit a voucher and for a manager to approve or disapprove it. The voucher entity itself will hold only minimal information.

Getting ready

The illustration of security will be based on a series of classes:

  • Voucher – An entity holding travel-related information
  • VoucherFacade – A facade class for the entity
  • AbstractFacade – The base class of the VoucherFacade
  • VoucherManager – A class used to manage vouchers and where most of the security techniques will be demonstrated
  • SecurityServlet – A servlet used to drive the demonstrations

All of these classes will be members of the packt package in the EJB module except for the servlet which will be placed in the servlet package of the WAR module.

How to do it…

Create a Java EE application called SecurityApplication with an EJB and a WAR module. Add a packt package to the EJB module and an entity called Voucher to the package.

Add five private instance variables to hold a minimal amount of travel information: name, destination, amount, approved, and an id. Also, add a default and a three argument constructor to the class to initialize the name, destination, and amount fields. The approved field is also set to false. The intent of this field is to indicate whether the voucher has been approved or not. Though not shown below, also add getter and setter methods for these fields. You may want to add other methods such as a toString method if desired.

@Entity
public class Voucher implements Serializable {
private String name;
private String destination;
private BigDecimal amount;
private boolean approved;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

public Voucher() {

}

public Voucher(String name, String destination,
BigDecimal amount) {
this.name = name;
this.destination = destination;
this.amount = amount;
this.approved = false;
}

}


Next, add an AbstractFacade class and a VoucherFacade class derived from it. The VoucherFacade class is shown below. As with other facade classes found in previous chapters, the class provides a way of accessing an entity manager and the base class methods of the AbstractFacade class.

@Stateless
public class VoucherFacade extends AbstractFacade<Voucher> {
@PersistenceContext(unitName = “SecurityApplication-ejbPU”)
private EntityManager em;

protected EntityManager getEntityManager() {
return em;
}

public VoucherFacade() {
super(Voucher.class);
}

}


Next, add a stateful EJB called VoucherManager. Inject an instance of the VoucherFacade class using the @EJB annotation. Also add an instance variable for a Voucher. We need a createVoucher method that accepts a name, destination, and amount arguments, and then creates and subsequently persists the Voucher. Also, add get methods to return the name, destination, and amount of the voucher.

@Stateful
public class VoucherManager {
@EJB
VoucherFacade voucherFacade;

Voucher voucher;

public void createVoucher(String name, String destination,
BigDecimal amount) {
voucher = new Voucher(name, destination, amount);
voucherFacade.create(voucher);
}

public String getName() {
return voucher.getName();
}

public String getDestination() {
return voucher.getDestination();
}

public BigDecimal getAmount() {
return voucher.getAmount();
}

}


Next add three methods:

  1. submit – This method is intended to be used by an employee to submit a voucher for approval by a manager. To help explain the example, display a message showing when the method has been submitted.
  2. approve – This method is used by a manager to approve a voucher. It should set the approved field to true and return true.
  3. reject – This method is used by a manager to reject a voucher. It should set the approved field to false and return false.

@Stateful
public class VoucherManager {

public void submit() {
System.out.println(“Voucher submitted”);
}

public boolean approve() {
voucher.setApproved(true);
return true;
}

public boolean reject() {
voucher.setApproved(false);
return false;
}
}


To complete the application framework, add a package called servlet to the WAR module and a servlet called SecurityServlet to the package. Use the @EJB annotation to inject a VoucherManager instance field into the servlet.

In the try block of the processRequest method, add code to create a new voucher and then use the submit method to submit it. Next, display a message indicating the submission of the voucher.

public class SecurityServlet extends HttpServlet {

@EJB
VoucherManager voucherManager;

protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType(“text/html;charset=UTF-8”);
PrintWriter out = response.getWriter();
try {
voucherManager.createVoucher(“Susan Billings”,
“SanFrancisco”, BigDecimal.valueOf(2150.75));
voucherManager.submit();
out.println(“<html>”);
out.println(“<head>”);
out.println(“<title>Servlet SecurityServlet</title>”);
out.println(“</head>”);
out.println(“<body>”);
out.println(“<h3>Voucher was submitted</h3>”);
out.println(“</body>”);
out.println(“</html>”);

} finally {
out.close();
}
}

}


Execute the SecurityServlet. Its output should appear as shown in the following screenshot:

Tutorial on EJB 3.1 Security

How it works…

In the Voucher entity, notice the use of BigDecimal for the amount field. This java.math package class is a better choice for currency data than float or double. Its use avoids problems which can occur with rounding. The @GeneratedValue annotation, used with the id field, is for creating an entity facade.

In the VoucherManager class, notice the injection of the stateless VoucherFacade session EJB into a stateful VoucherManager EJB. Each invocation of a VoucherFacade method may result in the method being executed against a different instance of VoucherManager. This is the correct use of a stateless session EJB. The injection of a stateful EJB into a stateless EJB is not recommended.

 

LEAVE A REPLY

Please enter your comment!
Please enter your name here