In certain situations, the identity of the user may need to be changed to enable a different, possibly more powerful, role. Consider the following analogy:
If you are familiar with the way most operating systems work, a user is not permitted to directly read or write to a file. Low-level access to the file is restricted. When a user needs to read or write to a file, the operating system will verify the individual's access rights to the file and then temporarily grant read/write access privileges to the user. The user assumes a higher level of privilege on a temporary basis.
This is analogous to the use of the @RunAs annotation. It allows a new role to be temporarily assigned to the methods of an EJB.
The steps used to propagate an identity include:
When a method of the second EJB is invoked from the first EJB, the identity (principal) is passed with the invocation as part of the security context. The @RunAs annotation is used to temporarily assign a new role to the current principal. When the second class' methods are invoked, the new role is assumed.
This annotation is applied at the class level. The annotation has a single argument, a string containing the name of the role. Only one role can be assumed at a time.
@RunAs("manager")
When the @RunAs annotation is used, it is normally used in conjunction with the @DeclareRoles annotation.
We will add another class to the packt
package to demonstrate the use of the @RunAs annotation. Let's assume when a voucher is submitted it should be verified. If it fails verification, then an exception can be thrown. In this example, we will not throw an exception so as to keep it simple. An additional restriction, which we will use to illustrate this technique, requires the methods of this verification EJB to run in the manager role.
Add a class to the packt
package called VoucherVerification
. Annotate the class with the @RunAs annotation using a value of "manager". In the class, inject a SessionContext
object using the @Resource annotation. Add a submit
method which passes and returns void
. In the method, add code to use the SessionContext
variable to return a principal object. This principal represents the user who invoked the method. The getCallerPrincipal
method returns a Principal
object. Follow the call with a println
method invoking the getName
method of the principal to display the principal's name.
@Stateless @DeclareRoles("manager") @RunAs("manager") public class VoucherVerification { @Resource private SessionContext sessionContext; public void submit() { Principal principal = sessionContext.getCallerPrincipal(); System.out.println("Principal: " + principal.getName()); // Perform verification checks } }
Modify the VoucherManager
class to inject an instance of the VerificationManager
class. Modify its submit
method to call the VerificationVoucher's submit
method.
public class VoucherManager { ... @EJB VoucherVerification voucherVerification; ... @RolesAllowed("employee") public void submit() { System.out.println("Voucher submitted"); voucherVerification.submit(); } ... }
Modify the SecurityServlet
try block to appear as follows:
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(); out.println("<h3>Voucher name: " + voucherManager.getName() + "</h3>"); out.println("</body>"); out.println("</html>");
Execute the application using the user, "mary", first and then "sally". The output from the println
method reflects the different users.
INFO: Voucher submitted
INFO: Principal: mary
INFO: Voucher submitted
INFO: Principal: sally
Even though the user, "sally", is not a manager, the submit
method is still executed.
The VoucherManager's submit
method executed using the role of employee. However, we decided the VoucherValidation's submit
method needed to run in the manager role. Allowing an employee to temporarily use the manager role was achieved using the @RunAs annotation.
The use of the @RunAs annotation should be used with care. Sufficient checks should be made to ensure the selected method is executed only when any restrictions placed on its use have been met. In a sense, we are augmenting declarative security with a set of criteria to meet special conditions.
3.144.222.185