Exploring J2EE Security Across All Tiers

The J2EE architecture supports secure deployment of applications and components. It provides you with both programmatic and declarative security approaches. Software problems are magnitudes of times more costly to find and repair after deployment. J2EE emphasizes the cost-effective declarative approach, in which application code is driven and managed according to the security policies. This enhances the portability and flexibility of deploying enterprise applications. Similar to transactions and persistence, J2EE expresses and manages security requirements (roles and access control) outside the application code in XML-based deployment descriptors.

The programmatic security approach explicitly allows you to add security rules and checks to the application code. This is particularly useful in situations in which special security rules across EJB or JSP components' call chains cannot be implemented using the declarative approach. For example, an application might make authorization decisions based on certain factors, such as user information stored in a database.

The J2EE architecture provides an end-to-end global security that spans multiple tiers. It supports the propagation of the security context for components along a call chain, across components that are hosted in different tiers. This eliminates the need for the user information to be passed as parameters in the business method calls, thereby providing reliability and ease of programming. It also supports the concept of a single sign-on (SSO) to access applications. The security context can be propagated across multiple J2EE servers that use different security realms in the production environment. It also propagates the security context to Common Object Request Broker Architecture (CORBA)-based applications over the IIOP protocol through the EJB to CORBA mapping. Figure 19.3 illustrates security context propagation across multiple J2EE components, tiers, and servers.

Figure 19.3. J2EE security context propagation.


The following sections will help you examine how the authentication and authorization security mechanisms work across the J2EE tiers. You'll explore each type of applications in each tier, and the recommended security mechanisms.

Client Tier Security

Security on the client tier is applied to either a standalone Java application or to a J2EE client application that runs on its own container. The other type of client is a Web-based client that runs within the browser container, which will be discussed in the section on Web tier security.

J2EE Client Application

A J2EE client application is a J2EE component that's deployed in the J2EE client container. When a J2EE client application is launched, a login window provided by the EJB container pops up and asks the user to input his user ID and password. After the user is authenticated, the application is started and its components become functional. The authenticated user security context is established at the EJB tier and propagated across other tiers or servers as needed. The J2EE architecture encourages the use of a J2EE client application rather than a standalone Java application. This method of authentication is best used in highly customized Intranet applications. A J2EE client application can use JAAS authentication, which will be discussed later today.

Standalone Java Application

J2EE does not specify how to authenticate users with standalone Java applications. However, some J2EE container providers use the JNDI authentication mechanism, as discussed in Day 4, to authenticate standalone users.

Web Tier Security

J2EE supports both authentication and authorization for Web tier components. The Web tier is probably the first entry point for most browser-based applications, and is where user authentication takes place. In the next few sections, we'll explore the methods of authentication at the Web tier, and we'll highlight the use of the declarative and programmatic approaches in authorization.

HTTP BASIC Authentication

This is the simplest type of authentication. The keyword BASIC is used in the <auth-method> element. When a user attempts to access any secure resource, the Web container uses the browserís login screen to solicit the user ID and password from the user in order to perform authentication. This is also considered to be a part of the client tier authentication mechanism for a Web-based client application.

<web-app>
. . .
<login-config>
   <auth-method>BASIC</auth-method>
   <realm-name>default</realm-name>
</login-config>
. . .
</web-app>

Form-Based Authentication

Form-based authentication is another declarative authentication approach available to the Web tier for configuring a login method. In the web.xml deployment descriptor of the WAR file, the value of the <auth-method> subelement is set to FORM. Here's an example of the <login-config> element of the web.xml file:

<web-app>
. . .
  <login-config>
    <auth-method>FORM</auth-method>
      <form-login-config>
        <form-login-page>login.jsp</form-login-page>
        <form-error-page>error.jsp</form-error-page>
      </form-login-config>
  </login-config>
. . .
</web-app>

In the preceding example, the user will be automatically presented with the login.jsp page for authentication, if not already authenticated.

Form-based authentication is used if an application requires a special login screen. The web.xml deployment descriptor must specify the login form page using the <form-login-page> element, and the error page using <form-error-page> element, as specified in the FORM authentication shown earlier. When a user attempts to access a secure resource, the Web container presents the login form as specified in the deployment descriptor. The following is an example of a JSP page incorporating form-based security authentication:

<form method="POST" name="Login" action="j_security_check">
								<input type="text" name="j_username">
								<input type="password" name="j_password">
    <input type="submit" value="Login" name="Submit">
</form>

Note

In the preceding form-based authentication example, the form named Login must contain fields named precisely j_username and j_password to represent the username and password, respectively.


Caution

Neither HTTP BASIC authentication nor form-based authentication is secure—the content of the user dialog is sent as plain text, and the target server is not authenticated.


HTTPS Authentication

The HTTP over SSL protocol can be used for authentication purposes. SSL is a powerful mechanism, which requires the user's public key to encrypt passwords. This is commonly used for Web-based e-commerce applications as well as single sign-on requirements. This is accomplished by simply running an instance of the HTTPS server for authentication purposes.

Hybrid Authentication

In both BASIC and form-based authentication, passwords are not encrypted. This deficiency can be overcome by running HTTP BASIC and form-based authentication mechanisms over SSL. In general, the use of the CONFIDENTIAL flag in the <transport-guarantee> element of the web.xml ensures the use of SSL for data transmission.

<web-app>
. . .
<security-constraint>
. . .
   <user-data-constraint>
      <transport-guarantee>CONFIDENTIAL</transport-guarantee>
   </user-data-constraint>
</security-constraint>
. . .
</web-app>

Note

This technique is different from HTTPS authentication, which is based on running a separate instance of the HTTPS server. The hybrid technique is based on the deployment descriptor setting, which will be enforced by the Web container.


Most Web container providers support the concept of a single sign-on, so that one login session can propagate across multiple applications. A flag of NONE means that the application does not require any transport guarantee, whereas a flag of INTEGRAL means that transmitted data cannot be changed in transit.

Web Component Declarative Authorization

In a Web application, authorization is performed by defining roles, and then specifying how these roles are allowed accessing to the protected resources (such as JSPs and servlets). The role is defined using the <role-name> element of the web.xml deployment descriptor:

<web-app>
  . . .
  <security-role>
    <role-name>Registrar</role-name>
  </security-role>
. . .
</web-app>

Resources are protected by using one or more <web-resource-collection> elements. Each <web-resource-collection> element contains an optional series of <url-pattern> elements followed by an optional series of <http-method> elements. The <url-pattern> element value specifies a URL pattern, which must match for the request to access the protected resource. The <http-method> element value specifies a type of HTTP request to allow (GET or POST). The following is an example of declarative authorization to the welcomeServlet resource:

<web-app>
  . . .
<security-constraint>
    <web-resource-collection>
								<web-resource-name>Welcome Servlet</web-resource-name>
								<url-pattern>/welcomeServlet</url-pattern>
								<http-method>GET</http-method>
								</web-resource-collection>
    <auth-constraint>
      <role-name>Registrar</role-name>
    </auth-constraint>
. . .
</security-constraint>
. . .
</web-app>

Developers may declare one or more <security-role-ref> elements to protect their Web components in the application's deployment descriptors. These elements are used to reference an existing <role-name> value set by the application assembler.

A more flexible approach of deploying secure Web applications, the <role-name> element value can be linked (by the deployer) to an already defined <security-role> element through the <role-link> element. The following is an example of a web.xml deployment descriptor to illustrate these concepts:

<web-app>
. . .
 <servlet>
   <servlet-name>HelloServlet</servlet-name>
 </servlet>
   ...
 <security-role-ref>
								<role-name>Registrar</role-name>
								<role-link>AdminRole</role-link>
								</security-role-ref>
...
</web-app>

Web Component Programmatic Authorization

This section discusses the programmatic approach to use for cases in which the declarative approach is not sufficient. The getRemoteUser(), getUserPrincipal(), and isUserInRole() methods are available in the HttpServletRequest interface to provide servlets and JSPs with access to security context information.

The getRemoteUser() method obtains the name of the authenticated user, whereas the getUserPrincipal() method returns the principal object associated with the authenticated user. The isUserInRole(String roleName) queries the underlying security realm to determine whether the authenticated caller belongs to a given security role. This may be useful for dynamically verifying that a Registrar role, for example, should be able to update or delete data.

In the HelloServlet code that follows, we use the HttpServletRequest to access CallerPrincipal. Also, to perform sensitive operations, we check on the user role as specified in the web.xml.

// Obtain the principal from the HTTPServletRequest object
CallerPrincipal callerPrincipal = request.getCallerPrincipal();
// obtain the caller principal's name
out.println("User name :" + callerPrincipal.getName());
// Check if the caller belongs to <role-name>
if (request.isUserInRole("Registrar")) {
   // do things only allowed to the Registrar
}

Note

The preceding example uses both the declarative and programmatic approaches of security authorization.


EJB Tier Security

The EJB container supports both declarative and programmatic authorization approaches. When an EJB business method invokes another EJB using the other bean's home or component interface, the EJB container propagates the security context, including the principal and roles, from the invoking EJB to the invoked EJB. In the following sections, you will learn how to declare security rules in the EJB deployment descriptor ejb-jar.xml file. First, you'll learn how to define a security role, and reference it from your code. You also will learn how to link roles and how to secure EJB methods.

Defining Security Roles

The application assembler can optionally define one or more security roles in the ejb-jar.xml deployment descriptor. This definition uses the <role-name> element of the deployment descriptor. In the following snippet, the role name Registrar is defined as part of the <assembly-descriptor> tag:

<ejb-jar>
. . .
  <assembly-descriptor>
    <security-role>
      <description>
        This role is only allowed to Registrar
      </description>
      <role-name>Registrar</role-name>
								</security-role>
  <assembly-descriptor>
. . .
</ejb-jar>

Note

The description tag is optional in all elements of deployment descriptors.


The deployer then maps the physical groups and user accounts defined in the operational environment to the security roles defined by the application assembler. This is performed using the vendor-specific deployment descriptor. For example, WebLogic Server uses the weblogic-ejb-jar.xml deployment descriptor to map the role named Registrar to the principal Laura:

<weblogic-ejb-jar>
. . .
  <security-role-assignment>
     <role-name>Registrar</role-name>
     <principal-name>Laura</principal-name>
  </security-role-assignment>
</weblogic-ejb-jar>

As your learned earlier today, multiple principals can be assigned to the same role (in case one is on vacation!), as illustrated by following examples:

<weblogic-ejb-jar>
. . .
  <security-role-assignment>
     <role-name>Registrar</role-name>
     <principal-name>Laura</principal-name>
								<principal-name>Lillian</principal-name>
								<principal-name>Rudy</principal-name>
  </security-role-assignment>
</weblogic-ejb-jar>

Declaring Security Role References

The EJB developer is responsible for setting the <security-role-ref> elements of the deployment descriptor and the security role names used in the EJB code. Here's an example:

<ejb-jar>
 <enterprise-beans>
  ...
  <session>
   <ejb-name>UserManagerEJB</ejb-name>
   ...
   <security-role-ref>
    <description>
       This security role should be assigned to the
       Registrar of the registration office.
    </description>
    <role-name>Registrar</role-name>
								</security-role-ref>
</session>
  ...
</enterprise-beans>
...
</ejb-jar>

Note

The declared name must be the security role name that is used as a parameter to the isCallerInRole(String roleName) method.


Linking Security Role References to Security Roles

Declaring the security role references in the preceding code allows the assembler or the deployer to link the names of the security roles used in the code to the security roles defined for an assembled application through the defined <security-role> elements.

The application assembler links each security role reference to a security role using the <role-link> element. The value of the <role-link> element must be the name of one of the security roles defined in a <security-role> element. The following deployment descriptor example shows how to link the security role reference named Registrar to the security role named registration-office:

<ejb-jar>
...
 <enterprise-beans>
   ...
  <session>
   <ejb-name>UserManagerEJB</ejb-name>
   ...
   <security-role-ref>
     <description>
       This role should be assigned to the
       Registrar of the registration office.
       The role has been linked to the
       Registration-office role.
     </description>
     <role-name>Registrar</role-name>
								<role-link>registration-office</role-link>
								</security-role-ref>
   ...
  </session>
  ...
 </enterprise-beans>
...
</ejb-jar>

Securing EJB Methods

The EJB container authorizes access to EJB components based on the user's security context, in conjunction with the permissions configured in the ejb-jar.xml deployment descriptor. The assembler is responsible for setting the method permissions, which is achieved by using both the <role-name> and <method-permission> elements of the <assembly-descriptor> tag.

The following ejb-jar.xml fragment grants permissions to an authenticated user in the role of Registrar for all the methods (indicated by the *) of the home and remote interfaces of the UserManagerEJB bean:

<ejb-jar>
...
  <assembly-descriptor>
    . . .
    <method-permission>
      <role-name>Registrar</role-name>
      <method>
        <ejb-name>UserManagerEJB</ejb-name>
        <method-name>*</method-name>
      </method>
    </method-permission>
  </assembly-descriptor>
. . .
</ejb-jar>

You can selectively specify certain methods when granting access. The following example grants permissions to only the enrollStudent() method of the same UserManagerEJB:

<method-permission>
   <role-name>student</role-name>
   <method>
     <ejb-name>UserManagerEJB</ejb-name>
     <method-name>enrollStudent</method-name>
   </method>
</method-permission>

A more fine-grained level, when you need to grant access to a certain overloaded method (which has the same name but different parameters), is to specify the parameter types of the method in a group of the <method-param> elements:

<method-permission>
    <role-name>student</role-name>
    <method>
       <ejb-name>UserManagerEJB</ejb-name>
       <method-name>enrollStudent</method-name>
       <method-params>
								<method-param> java.lang.String </method-param>
								<method-param> java.lang.Integer </method-param>
								</method-params>
    </method>
</method-permission>

Caution

You must specify the full class name for each parameter of the method.


Using <run-as> to Delegate Security

The application assembler can use the <run-as> element to define a run-as identity for an EJB in the deployment descriptor. This applies to all the methods of the EJB or to the onMessage() method of a message-driven bean, and all internal methods of the invoked beans.

Because the application assembler does not, in general, know the security environment of the operational environment, the run-as identity is designated by a logical <role-name>, which is delegated to one of the security roles defined by the application assembler in the deployment descriptor. The deployer then assigns a security principal defined in the operational environment to be used as the principal for the run-as identity.

The <run-as> element in the following example is used to provide access to only the Registrar role. This type of exclusionary access is useful in situations in which you want to protect internal EJBs from external user access.

<ejb-jar>
...
<enterprise-beans>
   ...
   <session>
      <ejb-name>UserManagerEJB</ejb-name>
      ...
      <security-identity>
        <run-as>
								<role-name>Registrar</role-name>
								</run-as>
      </security-identity>
      ...
    </session>
    ...
</enterprise-beans>
...

EJB Component Programmatic Authorization

Similar to Web components, EJB components can perform programmatic authorization. The EJBContext provides EJB components access into the security and transaction contexts. EJBContext provides two methods to allow programmatic authorization: getCallerPrincipal() and isCallerInRole().

getCallerPrincipal() allows the EJB component to obtain the principal object associated with the caller. getCallerPrincipal() is commonly used from within a session bean to access another entity bean using the principal as the primary key. This approach allows sensitive data for retrieval purposes to be obtained from the EJBContext. The method isCallerInRole(String roleName) is used in the same fashion as in the “Web Component Programmatic Authorization” section earlier today. The following example illustrates the use of the getCallerPrincipal() method:

// Obtain the default initial JNDI context.
Context ctx = new InitialContext();
// Look up the remote home interface of the StudentEJB
Object ojb = ctx.lookup("java:comp/env/ejb/StudentEJB");
// Convert obj to the proper type.
StudentHome student = (StudentEJBHome)
          javax.rmi.PortableRemoteObject.narrow(obj, StudentEJBHome.class);
// obtain the caller principal, and name
								CallerPrincipal callerPrincipal = ejbContext.getCallerPrincipal();
								String callerKey = callerPrincipal.getName();
// use the name as primary key to StudentEJB finder
StudentEJB myStudent = student.findByPrimaryKey(callerKey);
// update the studentís phone number
myStudent.changePhoneNumber(...);

The preceding code fragment obtains the principal name of the current caller by using the ejbContext to locate the student, and updates the student's phone number.

Note

Although J2EE emphasizes the use of declarative authorization, we explained programmatic authorization for completeness.


EIS Tier Security

J2EE supports both declarative and programmatic approach in the EIS tier. In the declarative approach, the application component requests a connection to an EIS resource using JNDI authentication (the JNDI access mechanism was covered in Day 4). With this approach, the container manages the authentication of the EIS resource. The container determines the username and password for establishing a connection to an EIS instance from the configuration files or from the command line.

With the programmatic approach, the component manages the authentication to the EIS resource. We explored the programmatic approach to accessing a JDBC resource in Day 4, in the section “Using JNDI in User Authentication.” The programmatic approach to accessing a JMS resource is explained in Day 13, “Understanding JMS and Message-Driven Beans,” in the section “Step 2: Create a QueueConnection.”

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.247.181