CONTENTS | PREV | NEXT | INDEX J2EE BluePrints



10.11 Security

This section describes the sample application's security requirements and discusses the ways these requirements are addressed using the J2EE security framework.


10.11.1 Requirements

The pet store application is designed to be deployed on the Internet. Like many Web-based e-commerce applications, it allows anyone to interact with and use the application. Any user, regardless of whether they're a registered customer, can point a browser at the start URL of the application and browse through the catalog, viewing items, prices, inventory status, and so on. We call this tire kicking, and this class of users tirekickers.

A new customer can sign up using a form presented by the application. Once a customer has signed up, the customer can sign in, by providing a user name and password to the application. Only customers who have signed in are allowed to place orders and view order status. When an order is placed, the payment details, including the credit card number, must be transmitted in a secure manner.

Some users of the pet store application may receive special treatment. For example, a frequent shopper may a preferred customer, able to receive discounts or awards not available to normal customer. Another class of special user might be system administrators, with unlimited access to information on the site. For example, they might be able to fetch a list of all orders placed after a certain date.

These high-level functional requirements translate into the following security requirements:

User Authentication

Users of the pet store application can be either authenticated or unauthenticated. The user must be authenticated to access a protected resource. The application should be able to identify, differentiate, and be able to make access control decisions based on this distinction.
There should be a way to associate each authenticated user with one or more categories. For example, user A could be recognized as a customer, while user B could be recognized as a preferred customer.

Authorization

The application associates permissions with resources such as Web pages or enterprise bean methods. Examples of the kind of authorization constraints the application should allow:
  - Anyone (authenticated or not), to see the URL /control/product, or invoke the getProducts method of Catalog
  - All authenticated users to see the URL /control/placeorder
  - Only preferred users to see the URL /control/discounts

Confidentiality

Some user information, such as a credit card number, must be transmitted confidentially to the application.

User Administration

The sample application has its own set of users. This set of users grows when new users add themselves using a Web-based interface. Note that other applications, such as those developed for in-house use within an enterprise assume and use the set of users defined in the operational environment. The sample application does not depend on the operational environment to get its set of users.

10.11.2 Implementation

The pet store application uses many features of the J2EE platform to address its security requirements in a simple and transparent manner. By design, security in the J2EE platform is mostly declarative. In some places however, we make security decisions in our components programmatically, because we needed to make authorization decisions based on the content or state of the object.

10.11.2.1 User Authentication

A J2EE application must be capable of authenticating users that access the application from a variety of clients. This section describes how the pet store application authenticates users of the shopping interaction Web client, how it could authenticate users of an administration application client, and how it handles unauthenticated users.


Web Client Authentication

Most of the interactions with the sample application occur through the Web-based interface. Form-based authentication, one of the standard authentication mechanisms in the J2EE architecture, is used to authenticate these interactions.

In form-based authentication, a Web container designates an application-specific page containing an HTML form for logging in. The sample application uses the page login.jsp as this page. This page contains an HTML form that prompts for a user name and password and is displayed when the user tries to access a resource that has been designated as being protected. The sample application also uses form-based authentication to enable:


<jsp:useBean id="last_login" class="...">
<% if (last_login.getTime() - currentTime < ... { %>
<font color="red">Login failed, try again<p></font>
<% } %>
Code Example 10.23 login.jsp

private void checkForWebServerLogin(HttpServletRequest req) {
	if ((req.getUserPrincipal() != null) &&
		!req.getUserPrincipal().getName().equals("guest") &&
		!mm.getAccountModel().isLoggedIn()) {
			EStoreEvent loginEvent = null;
			loginEvent = eventTranslator.createLoginEvent(req);
		...
Code Example 10.24 Triggering the Login Event
Let's look at the condition being tested. We first check if the principal is set on the current call. If it is, it means that some user is currently logged in. Next we check if our account bean knows about it. If accountBean.isLoggedIn returns false, it means that the account bean is not aware of the login yet. This is exactly the condition when we want to trigger the login event. Once the login event is processed, account.isLoggedIn would return true.

Application Client Authentication

In the J2EE platform, stand-alone clients are authenticated by an application client container. The application client may authenticate its user in a number of ways. The techniques used are platform-dependent and not under control of the application client. The application client container may integrate with the platform's authentication system, providing a single signon capability. The application client container may authenticate the user when the application is started. The application client container may use lazy authentication, only authenticating the user when it needs to access a protected resource. The J2EE specification does not describe the technique used to authenticate the user.

The J2EE SDK generates a client JAR file1 when enterprise beans are deployed. This library contains stub classes for accessing enterprise beans as well as a mechanism provided by the J2EE SDK for handling authentication to an EJB server.


Handling Unauthenticated Users

The sample application allows for anonymous, unauthenticated users to access the application and browse selected features of the pet store. Even in such cases, calls to the EJB tier must specify a valid principal; the EJB container rejects all calls without a security principal. That is, if the user invokes a feature that tries to call the EJB tier without authentication, the EJB container will not let the call go through.

However, since the Web interface needs to support anonymous, unauthenticated users, the J2EE platform defines a mechanism to do so. The responsibility for ensuring that unauthenticated calls are made using some principal is delegated to the EJB client container. In the sample application, the Web container performs this role by:

  - The getUserPrincipal method of the servlet API returns null for such users.
  - The form-based or other authentication mechanism will be activated when a protected Web resource is accessed.
10.11.2.2 Authorization

Sample application security is specified in terms of the security roles customer and gold_customer.

By default, the J2EE SDK assigns the ANYONE role to an enterprise bean method. The guest user, which is anonymous and unauthenticated, is assigned to the ANYONE role.

In the sample application, access to the URLs /control/signin (described in Section 10.11.2.1) and /control/placeorder is restricted to the roles customer and gold_customer. The security-constraint declaration for /control/signin is shown in Code Example 10.25.


<security-constraint>
	<web-resource-collection>
		...
		<url-pattern>/control/signin</url-pattern>
		<http-method>POST</http-method>
		<http-method>GET</http-method>
	</web-resource-collection>
	<auth-constraint>
		<description>no description</description>
		<role-name>gold_customer</role-name>
		<role-name>customer</role-name>
	</auth-constraint>
	...
</security-constraint>
Code Example 10.25 Security Constraint Declaration

In the current release, the sample application does not limit enterprise bean method invocation to specific security roles.

10.11.2.3 Confidentiality

Confidentiality constraints are specified at deployment time by setting the transport-guarantee element in the Web component's deployment descriptor to CONFIDENTIAL. In the current release, the sample application doesn't demonstrate confidentiality mechanisms.

10.11.2.4 User Administration

Many applications will need to perform two tasks that aren't handled by the J2EE platform: managing user profile information (other than security credentials and attributes) and adding new users to the system dynamically.


Maintaining User Profiles

In addition to keeping security credentials, the sample application needs other information about the user's preferences and personalization. The J2EE security framework will keep the security credentials, such as the user name and password, as well as attributes such as the set of roles that the user belongs to. The sample application needs another mechanism to maintain additional information for a user.

To do so, it maintains a separate relational table for user profile information. This table is called the accounts table, and is accessed through the Account enterprise bean. The user name is unique for each sample customer, and we use it as a key to the accounts database. Code Example 10.26 shows how the getCallerPrincipal method is used to retrieve the userId of the user making the current enterprise bean method call. The value returned from this method is used as a key to retrieve profile information for the user.


public Account getAccount() {
	if (acct == null) {
		try {
			String userId = sc.getCallerPrincipal().getName();
			AccountHome home = EJBUtil.getAccountHome();
			acct = home.findByPrimaryKey(userId);
		} catch (FinderException fe) {
			...
		} catch (RemoteException re) {
			throw new EJBException (re);
		}
	}
	return acct;
}
Code Example 10.26 ShoppingClientControllerEJB.getAccount

Adding New Users

The J2EE platform does not standardize a mechanism to add users dynamically to applications. Any application that requires this feature needs to do so in a non-portable, container-specific manner.

In such a situation, it makes sense to isolate all the non-portable code in one place. This small piece of platform-specific code can later be replaced if the application needs to be ported to a different container implementation.

The J2EE SDK provides a container-specific API for managing users based on the concept of realms. A realm is a collection of users under the same authentication policy. An application can provide its own realm and plug it into the J2EE SDK for the container to use for authentication, or it can use realm API methods such addUser, on the existing default J2EE realm.

The sample application uses the default J2EE realm. It uses the addUser method of the realm to add new users while processing the signup.jsp form.

In addition to specifying the user name and password of the user being added, we also need to specify the roles that this new user can assume. This is achieved through the addUser method, which takes an array of roles as an argument.

10.11.2.5 Programmatic Security

The J2EE platform encourages the use of declarative security. However there are places where one needs to make access control decisions based on the current state of the system. Such decisions must be made by programmatically encoding their rules in the application.

The J2EE platform allows the application to identify the principal making the call as well as the role that the caller is in, in both the Web and EJB tiers. The sample application uses these facilities as follows.


Web Tier

In the Web tier, the sample application uses the getUserPrincipal and the isUserInRole methods as follows:


EJB Tier

In the EJB tier, the sample application uses getCallerPrincipal and isCallerInRole methods as follows:


private int getBonusMiles() {
	int miles = (totalPrice >= 100) ? 1000 : 500;
	if (context.isCallerInRole("GOLD_CUSTOMER"))
		miles += 1000;
	return miles;
}
Code Example 10.27 OrderEJB.getBonusMiles

Notice the use of the embedded role name GOLD_CUSTOMER. When role names are embedded in the code, the Application Component Provider needs to identify these roles in a deployment descriptor so that the Deployer can ensure that they are mapped correctly when the application is deployed. Code Example 10.28 shows the portions of the sample application deployment descriptor where this happens.


		<security-role-ref>
		<role-name>GOLD_CUSTOMER</role-name>
		<role-link>gold_customer</role-link> 
	</security-role-ref>
	...
	<assembly-descriptor>
		<security-role>
			<role-name>gold_customer</role-name>
		</security-role>
		...
		</assembly-descriptor>
Code Example 10.28 Deployment Descriptor Element for Embedded Roles

In this excerpt from the deployment descriptor, the Application Component Provider declares the use of GOLD_CUSTOMER in the application using the security-role-ref element. The Deployer must ensure that this role is linked to the gold_customer security role.



CONTENTS | PREV | NEXT | INDEX
Copyright © 2001 Sun Microsystems, Inc. All Rights Reserved.