EJB 3.1: Controlling Security Programmatically Using JAAS

EJB 3.1 Cookbook


June 2011

$32.99

Enterprise JavaBean 3.1 - Build real world EJB solutions with a collection of simple but incredibly effective recipes with this book and eBook

 

EJB 3.1 Cookbook

EJB 3.1 Cookbook

Build real world EJB solutions with a collection of simple but incredibly effective recipes

        Read more about this book      

(For more resources on EJB, see here.)

The reader is advised to refer the initial two recipies from the previous article on the process of handling security using annotations.

Getting ready

Programmatic security is affected by adding code within methods to determine who the caller is and then allowing certain actions to be performed based on their capabilities. There are two EJBContext interface methods available to support this type of security: getCallerPrincipal and isCallerInRole. The SessionContext object implements the EJBContext interface. The SessionContext's getCallerPrincipal method returns a Principal object which can be used to get the name or other attributes of the user. The isCallerInRole method takes a string representing a role and returns a Boolean value indicating whether the caller of the method is a member of the role or not.

The steps for controlling security programmatically involve:

  1. Injecting a SessionContext instance
  2. Using either of the above two methods to effect security

How to do it...

To demonstrate these two methods we will modify the SecurityServlet to use the VoucherManager's approve method and then augment the approve method with code using these methods.

First modify the SecurityServlet try block to use the following code. We create a voucher as usual and then follow with a call to the submit and approve methods.

out.println("<html>");
out.println("<head>");
out.println("<title>Servlet SecurityServlet</title>");
out.println("</head>");
out.println("<body>");

voucherManager.createVoucher("Susan Billings", "SanFrancisco",
BigDecimal.valueOf(2150.75));
voucherManager.submit();
boolean voucherApproved = voucherManager.approve();

if(voucherApproved) {
out.println("<h3>Voucher was approved</h3>");
} else {
out.println("<h3>Voucher was not approved</h3>");
}

out.println("<h3>Voucher name: " + voucherManager.getName() +
"</h3>");

out.println("</body>");
out.println("</html>");

Next, modify the VoucherManager EJB by injecting a SessionContext object using the @Resource annotation.

public class VoucherManager {
...
@Resource
private SessionContext sessionContext;

Let's look at the getCallerPrincipal method first. This method returns a Principal object (java.security.Principal) which has only one method of immediate interest: getName. This method returns the name of the principal.

Modify the approve method so it uses the SessionContext object to get the Principal and then determines if the name of the principal is "mary" or not. If it is, then approve the voucher.

public boolean approve() {
Principal principal = sessionContext.getCallerPrincipal();
System.out.println("Principal: " + principal.getName());
if("mary".equals(principal.getName())) {
voucher.setApproved(true);
System.out.println("approve method returned true");
return true;
} else {
System.out.println("approve method returned false");
return false;
}
}

Execute the SecurityApplication using "mary" as the user. The application should approve the voucher with the output as shown in the following screenshot:

EJB 3.1: Controlling Security Programmatically Using JAAS

Execute the application again with a user of "sally". This execution will result in an exception.

INFO: Access exception

The getCallerPrincipal method simply returns the principal. This frequently results in the need to explicitly include the name of a user in code. The hard coding of user names is not recommended. Checking against each individual user can be time consuming. It is more efficient to check to see if a user is in a role.

The isCallerInRole method allows us to determine whether the user is in a particular role or not. It returns a Boolean value indicating whether the user is in the role specified by the method's string argument. Rewrite the approve method to call the isCallerInRole method and pass the string "manager" to it. If the return value returns true, approve the voucher.

public boolean approve() {
if(sessionContext.isCallerInRole("manager")) {
voucher.setApproved(true);
System.out.println("approve method returned true");
return true;
} else {
System.out.println("approve method returned false");
return false;
}
}

Execute the application using both "mary" and "sally". The results of the application should be the same as the previous example where the getCallerPrincipal method was used.

How it works...

The SessionContext class was used to obtain either a Principal object or to determine whether a user was in a particular role or not. This required the injection of a SessionContext instance and adding code to determine if the user was permitted to perform certain actions.

This approach resulted in more code than the declarative approach. However, it provided more flexibility in controlling access to the application. These techniques provided the developer with choices as to how to best meet the needs of the application.

There's more...

It is possible to take different actions depending on the user's role using the isCallerInRole method. Let's assume we are using programmatic security with multiple roles.

@DeclareRoles ({"employee", "manager","auditor"})

We can use a validateAllowance method to accept a travel allowance amount and determine whether it is appropriate based on the role of the user.

public boolean validateAllowance(BigDecimal allowance) {
if(sessionContext.isCallerInRole("manager")) {
if(allowance.compareTo(BigDecimal.valueOf(2500)) <= 0) {
return true;
} else {
return false;
}
} else if(sessionContext.isCallerInRole("employee")) {
if(allowance.compareTo(BigDecimal.valueOf(1500)) <= 0) {
return true;
} else {
return false;
}
} else if(sessionContext.isCallerInRole("auditor")) {
if(allowance.compareTo(BigDecimal.valueOf(1000)) <= 0) {
return true;
} else {
return false;
}
} else {
return false;
}
}

The compareTo method compares two BigDecimal values and returns one of three values:

  • -1 – If the first number is less than the second number
  • 0 – If the first and second numbers are equal
  • 1 – If the first number is greater than the second number

The valueOf static method converts a number to a BigDecimal value. The value is then compared to allowance.

Summary

This article covered programmatic EJB security based upon the Java Authentication and Authorization Service (JAAS) API.


Further resources on this subject:


Books to Consider

comments powered by Disqus
X

An Introduction to 3D Printing

Explore the future of manufacturing and design  - read our guide to 3d printing for free