Declarative security allows users, defined by roles, to access methods of a class. This is accomplished using a series of annotations to permit either certain roles to use a method, to permit all roles to use a method, or to deny access for all roles.
The application developer needs to determine which users (roles) should be permitted to access which methods. Once this has been determined, the classes and methods are annotated to affect these decisions.
Declarative security can be achieved using any of several annotations including @RolesAllowed, @PermitAll, and @DenyAll annotations. Each of these annotations has restrictions on where they can be used.
Annotation |
Use With |
Description |
---|---|---|
@PermitAll |
Bean, Method |
Allows access by all users |
@DenyAll |
Method |
No roles are permitted access to the method |
@RolesAllowed |
Bean, Method |
A list of roles permitted access |
The steps used to control access include:
The @RolesAllowed is configured with either a single string or an array of strings. These strings are the names of the roles allowed access to the EJB or a method. When applied to a method, the assignment will override any class level assignment. Here the use of both an array and a single role are specified.
@RolesAllowed({"bankemployee", "bankcustomer"}) @RolesAllowed("bankemployee")
In the VoucherManager
EJB, add an @RolesAllowed annotation to both the approve
and reject
methods. Specify a role of manager.
@RolesAllowed("manager") public boolean approve() { voucher.setApproved(true); return true; } @RolesAllowed("manager") public boolean reject() { voucher.setApproved(false); return false; }
Next, modify the SecurityServlet's processRequest
method's try block to create a voucher and approve it using the approve
method. Also, display a message to indicate whether the voucher was approved or not and add a catch block at the end of the try block to handle any access exceptions. The javax.ejb.EJBAccessException
is thrown when an access restriction is violated.
voucherManager.createVoucher("Susan Billings", "SanFrancisco", BigDecimal.valueOf(2150.75)); boolean voucherApproved = voucherManager.approve(); ... if(voucherApproved) { out.println("<h3>Voucher was approved</h3>"); } else { out.println("<h3>Voucher was not approved</h3>"); } ... catch(EJBAccessException e) { System.out.println("Access exception"); }
Execute the servlet and enter "mary" as the user. The application should execute normally with the voucher being approved since "mary" is authorized to use the approve
method as shown in the following screenshot:
Close the browser and re-execute the servlet. This time, use "sally" as the user. Since "sally" is not authorized to use the approve method, an EJBAccessException
is thrown.
INFO: Access exception
The @PermitAll annotation permits access to the EJB or a specific method by all roles. Anyone is able to access and use such methods. This is the default annotation for methods. For example, the VoucherManager's getName
method is not annotated. Add the following statement to the SecurityServlet
immediately after the code which displays the voucher approval message.
out.println("<h3>Voucher name: " + voucherManager.getName() + "</h3>");
Execute the servlet using "mary". The voucher's username is displayed as illustrated in the following screenshot:
If we add the @PermitAll annotation to the getName
method we will see no change in behavior. So what is the use of this annotation?
At the class level, one or more roles may have been declared using the @DeclareRoles annotation. The @PermitAll annotation can be used to permit a method to be used by some role other than those declared at the class level. For example, use the following annotations for the VoucherManager
EJB:
@Stateful @DeclareRoles("manager") @RolesAllowed("manager") public class VoucherManager { ... }
In the SecurityServlet
, remove the code dealing with the submit
method.
try { 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)); out.println("<h3>Voucher name: " + voucherManager.getName() + "</h3>"); out.println("</body>"); out.println("</html>"); } catch(EJBAccessException e) { System.out.println("Access exception"); } finally { out.close(); }
Next, use the @RolesAllowed("manager") annotation only for the VoucherManager's approve
and reject
methods. Do not use annotations for any of the other methods. If the servlet is executed using a user in the manager role ("mary"), the application executes cleanly. However, if you log in as "sally", an exception occurs because "sally" is no longer an authorized user. This is to be expected.
Add the @PermitAll annotation to the createVoucher
and getName
methods. Re-execute the application using "sally". This time the application should execute correctly. While we have only specified the manager role for the class, the @PermitAll annotation allows other groups to use those methods.
The @DenyAll annotation denies access to all roles and users. However, this annotation has limited utility. If access to the method should be denied to all users, then it can easily be removed from the EJB.
The @PermitAll, @DenyAll, and @RolesAllowed annotations provided an easy-to-use mechanism for controlling access to methods based upon the user's role. When an unauthorized user attempted to access a method, an exception was thrown which was caught and dealt with.
However, sometimes it is necessary to allow an unauthorized user access to a method under certain conditions. The need for this access and how to achieve it is detailed in the next recipe.
3.14.131.212