3.10 Programmatic Security
Declarative security should always be used instead of programmatic security whenever possible. However, when declarative security is insufficient, it may be necessary to retrieve security-sensitive information programmatically from the container. This section explains how to retrieve the user's identity and privilege information programatically.
Applications that make use of programmatic security typically invoke the following EJB and servlet/JSP security APIs:
-
EJB method isCallerInRole() in interface javax.ejb.EJBContext. This method is used to test whether the current caller, the client, has been assigned to a specified security role.
-
EJB method getCallerPrincipal() in interface javax.ejb.EJBContext. This method is used to obtain a Principal object representing the current caller, the client.
-
Servlet/JSP method isUserInRole() in interface javax.servlet.http.HttpServletRequest. This method, similar to the EJB method isCallerInRole(), returns a boolean indicating whether the authenticated user, the client, is a member of the specified security role.
-
Servlet/JSP method getUserPrincipal() in interface javax.servlet.http.HttpServletRequest. This method, similar to the EJB method getCallerPrincipal(), returns a Principal object representing the current authenticated user, the client.
3.10.1 Retrieving Identity Information
The Java Servlet and EJB specifications provide mechanisms to programmatically obtain identity information about the user invoking a method on a servlet or an enterprise bean.
3.10.1.1 From a Servlet or JSP File
The HttpServletRequest object passed to a servlet method can be used to obtain information about the user invoking the method. Invoking the getRemoteUser() method on the HttpServletRequest object returns the name of the user if the user has been authenticated, null otherwise.
The getRemoteUser() method can be invoked as shown in Listing 3.12.
Listing 3.12. Retrieving the User Name from a Servlet
public void doGet(HttpServletRequest req, HttpServletResponse res) { // other code... // obtain the user name String userName = req.getRemoteUser(); // other code... }
The getUserPrincipal() method in the HttpServletRequest object returns the Principal object corresponding to the user if the user has been authenticated, null otherwise. The name of the user can then be obtained by calling the getName() method on the Principal object, if this not null, as shown in Listing 3.13.
Listing 3.13. Retrieving the Principal Object and the User Name from a Servlet
public void doGet(HttpServletRequest req, HttpServletResponse res) { // other code... // obtain the user Principal Principal userPrincipal = req.getUserPrincipal(); // obtain the user name String userName; if (userPrincipal != null) userName = userPrincipal.getName(); // other code... }
3.10.1.2 From an Enterprise Bean
The getCallerPrincipal() method can be called on a javax.ejb.EJBContext object to obtain the Principal object corresponding to the user making the enterprise bean method invocation. The Principal object can then be used to obtain information about the user. A code example is shown in Listing 3.14.
Listing 3.14. Retrieving the User Name from an Enterprise Bean
public String getUserName(EJBContext context) { // obtain and return the user name return context.getCallerPrincipal().getName(); }
3.10.2 Proactive Authorization
The Java Servlet and EJB specifications provide mechanisms to programmatically obtain information about the user's privileges by invoking a method on a servlet or an enterprise bean.
3.10.2.1 From a Servlet or JSP File
The HttpServletRequest object passed to a servlet method can be interrogated to obtain information about whether the user invoking the method has been granted a particular security role. Based on the result, the servlet may make decisions on how to proceed. For example, if the caller is granted the Boss role, the servlet redirects to a page that has managerial capabilities; otherwise, it might redirect to a different page. Note that when the servlet checks for the Boss role, this role is scoped to the servlet. The Application Assembler performs the mapping of this role reference to an enterprise application role by using the role-link tag in the deployment descriptor, as shown in Listing 3.15.
Listing 3.15. An XML role-link Element in a Deployment Descriptor
<security-role-ref> <role-name>Boss</role-name> <role-link>Manager</role-link> </security-role-ref>
A code example is shown in Listing 3.16.
Listing 3.16. Retrieving the User's Role Information from a Servlet
public void doGet(HttpServletRequest req, HttpServletResponse res) { // other code... if (req.isUserInRole("Boss")) { // code to redirect to Manager's page... } else { // code to redirect to generic page... } // other code... }
3.10.2.2 From an Enterprise Bean
The isCallerInRole() method on an EJBContext object can be used to obtain information about the roles granted to a particular user. This is similar to what we saw in Section 3.10.1.1 on page 92. A code fragment example is shown in Listing 3.17.
Listing 3.17. Retrieving the User's Role Information from an Enterprise Bean
public Object getOrganizationInfo(EJBContext context) { // other code... // obtain the user name if (context.isCallerInRole("Boss") { // code to access the Boss entity bean and get the // budget info... } else { // code to access the employee bean and get the // organization chart... } // other code... }
3.10.3 Application-Managed Sign-On to an EIS
Section 3.9.4 on page 87 described container-managed sign-on, whereby a connection to an EIS is obtained through declarative security. An alternative approach is to use programmatic security by allowing the sign-on to an EIS to be managed directly by the application. In order for a connection to be application managed, the value of the res-auth XML element associated with a resource definition in the deployment descriptor must be set to Application, as shown in Listing 3.18.
Listing 3.18. Setting the res-auth Deployment Descriptor Tag to Application
<resource-ref> <description>Connection to myConnection</description> <res-ref-name>eis/myConnection</res-ref-name> <res-type>javax.resource.cci.ConnectionFactory</res-type> <res-auth>Application</res-auth> </resource-ref>
In the case of application-managed sign-on, the application is responsible for retrieving appropriate user information, such as the user ID and password, necessary to connect to the EIS. The connection is facilitated by a resource adapter. The application invokes the getConnection() method on the ConnectionFactory instance with the security information: user ID and password. Specifying security information is dependent on the resource adapter type and the way in which the adapter accepts the user ID and password. For example, in order to connect to an EIS system called MyEIS, the application may be required to pass user ID and password through a com.myeis.ConnectionSpecImpl object. Listing 3.19 is a Java code fragment showing such a scenario, which is similar to the one discussed in Section 3.9.4 on page 87, except that the security information is coded into the application and is passed to the getConnection() method.