Programmatic security is code that is embedded in a business method, is used to access a caller's identity programmatically, and uses this information to make security decisions within the method itself.
In general, security management should be enforced by the container in a manner that is transparent to the enterprise beans’ business methods. The security API described in this section should be used only in the less frequent situations in which the enterprise bean business methods need to access the security context information, such as when you want to restrict access to a particular time of day.
The javax.ejb.EJBContext interface provides two methods that allow the bean provider to access security information about the enterprise bean’s caller.
java.security.Principal getCallerPrincipal();
The purpose of the getCallerPrincipal method is to allow the enterprise bean methods to obtain the current caller principal’s name. The methods might, for example, use the name as a key to information in a database.
The following code sample illustrates the use of the getCallerPrincipal() method:
@Stateless public class EmployeeServiceBean implements EmployeeService{ @Resource SessionContext ctx; @PersistenceContext EntityManager em; public void changePhoneNumber(...) { ... // obtain the caller principal. callerPrincipal = ctx.getCallerPrincipal(); // obtain the caller principal’s name. callerKey = callerPrincipal.getName(); // use callerKey as primary key to find EmployeeRecord EmployeeRecord myEmployeeRecord = em.find(EmployeeRecord.class, callerKey); // update phone number myEmployeeRecord.setPhoneNumber(...); ... } }
In this example, the enterprise bean obtains the principal name of the current caller and uses it as the primary key to locate an EmployeeRecord entity. This example assumes that application has been deployed such that the current caller principal contains the primary key used for the identification of employees (for example, employee number).
boolean isCallerInRole(String roleName);
The enterprise bean code can use the isCallerInRole(String roleName) method to allow the bean provider/application developer to code the security checks that cannot be easily defined using method permissions. Such a check might impose a role-based limit on a request, or it might depend on information stored in the database.
The enterprise bean code can use the isCallerInRole(String roleName) method to test whether the current caller has been assigned to a given security role. Security roles are defined by the bean provider or the application assembler, and are assigned to principals or principal groups that exist in the operational environment by the deployer.
The following code sample illustrates the use of the isCallerInRole(String roleName) method:
@Stateless public class PayrollBean implements Payroll { @Resource SessionContext ctx; public void updateEmployeeInfo(EmplInfo info) { oldInfo = ... read from database; // The salary field can be changed only by callers // who have the security role "payroll" if (info.salary != oldInfo.salary && !ctx.isCallerInRole("payroll")) { throw new SecurityException(...); } ... } ... }
You would use programmatic security in this way to dynamically control access to a method, for example, when you want to deny access except during a particular time of day. An example application that uses the getCallerPrincipal and isCallerInRole methods is described in Example: Using the isCallerInRole and getCallerPrincipal Methods.
This example demonstrates how to use the getCallerPrincipal() and isCallerInRole(String role) methods with an enterprise bean. This example starts with a very simple EJB application, converter, and modifies the methods of the ConverterBean so that currency conversion will only occur when the requester is in the role of TutorialUser.
The source code for the original converter application was modified as shown in the following code snippet (modifications in bold) to add the if..else clause that tests if the caller is in the role of TutorialUser. If the user is in the correct role, the currency conversion is computed and displayed. If the user is not in the correct role, the computation is not performed, and the application displays the result as 0.
The code snippet is as follows:
package converter.secure.ejb; import java.math.BigDecimal; import javax.ejb.*; import java.security.Principal; import javax.annotation.Resource; import javax.ejb.SessionContext; import javax.annotation.security.DeclareRoles; import javax.annotation.security.RolesAllowed; @Stateless() @DeclareRoles("TutorialUser") public class ConverterBean{ @Resource SessionContext ctx; private BigDecimal yenRate = new BigDecimal("96.0650"); private BigDecimal euroRate = new BigDecimal("0.0078"); @RolesAllowed("TutorialUser") public BigDecimal dollarToYen(BigDecimal dollars) { BigDecimal result = new BigDecimal("0.0"); Principal callerPrincipal = ctx.getCallerPrincipal(); if (ctx.isCallerInRole("TutorialUser")) { result = dollars.multiply(yenRate); return result.setScale(2, BigDecimal.ROUND_UP); }else{ return result.setScale(2, BigDecimal.ROUND_UP); } } @RolesAllowed("TutorialUser") public BigDecimal yenToEuro(BigDecimal yen) { BigDecimal result = new BigDecimal("0.0"); Principal callerPrincipal = ctx.getCallerPrincipal(); if (ctx.isCallerInRole("TutorialUser")) { result = yen.multiply(euroRate); return result.setScale(2, BigDecimal.ROUND_UP); }else{ return result.setScale(2, BigDecimal.ROUND_UP); } } }
After you've made the changes to the enterprise bean, follow the instructions in Compiling, Packaging, and Running the converter Example.
After you've made the changes to the enterprise bean, follow the instructions in Compiling, Packaging, and Running the converter Example.
Problem: The application displays zero values after authentication, as shown here:
appclient-command-common: [exec] $100.00 is 0.00 Yen. [exec] 0.00 Yen is 0.00 Euro. |
Solution: Verify that the user name and password that you entered for authentication match a user name and password in the Enterprise Server, and that this user is assigned to the group named TutorialUser. User names and passwords are case-sensitive. Read Adding Users to the Enterprise Server for more information on adding users to the file realm of the Enterprise Server.