| CONTENTS | PREV | NEXT | INDEX | Designing Enterprise Applications with the J2EETM Platform, Second Edition |
In distributed component computing, authentication is the mechanism by which callers and service providers prove to one another that they are acting on behalf of specific users or systems. When the proof is bidirectional, it is referred to as mutual authentication. Authentication establishes the call identities and proves that the participants are authentic instances of these identities. An entity that participates in a call without establishing or proving an identity (that is, anonymously) is called unauthenticated.
When a client program run by a user makes the calls, the caller identity is likely to be that of the user. When the caller is an application component acting as an intermediary in a call chain originating with some user, the identity may be associated with that of the user, in which case the component would be impersonating the user. Alternatively, one application component may call another with an identity of its own and unrelated to that of its caller.
Authentication is often achieved in two phases. First, an authentication context is established by performing a service-independent authentication requiring knowledge of some secret. The authentication context encapsulates the identity and is able to fabricate authenticators (proofs of identity). Then, the authentication context is used to authenticate with other (called or calling) entities. The basis of authentication entails controlling access to the authentication context and thus the ability to authenticate as the associated identity. Among the possible policies and mechanisms for controlling access to an authentication context are:
- Once the user performs an initial authentication, the processes the user starts inherit access to the authentication context.
- When a component is authenticated, access to the authentication context may be available to other related or trusted components, such as those that are part of the same application.
- When a component is expected to impersonate its caller, the caller may delegate its authentication context to the called component.
Some entities may communicate without requiring authentication. A protection domain is a set of entities that are assumed or known to trust each other. Entities in such a domain need not be authenticated to one another.
Figure 9.1 illustrates that authentication is only required for interactions that cross the boundary of a protection domain. When one component interacts with others in the same protection domain, no constraint is placed on the identity that it can associate with its call. The caller may propagate the caller's identity, or choose an identity based on knowledge of authorization constraints imposed by the called component, since the caller's ability to claim an identity is based on trust, not authentication. If the concept of protection domains is employed to avoid the need for authentication, there must be a means to establish the boundaries of protection domains so that trust in unproven identities does not cross these boundaries. Entities that are universally trusting of all other entities should not be trusted as a member of any protection domain.
In the J2EE architecture, a container provides an authentication boundary between external callers and the components it hosts. The boundaries of protection domains don't always align with those of containers. Containers enforce the boundaries, and implementations are likely to support protection domains that span containers. Although a container is not required to host components from different protection domains, an implementation may choose to do so.
For inbound calls, it is the container's responsibility to make an authentic representation of the caller identity available to the component in the form of a credential. An X.509 certificate and a Kerberos service ticket are examples of credentials used in computing environments. They are analogous to credentials such as a passport or a driver's license used in person-to-person interactions.
For outbound calls, the container is responsible for establishing the identity of the calling component. In general, it is the job of the container to provide bidirectional authentication functionality to enforce the protection domain boundaries of the deployed applications.
Without proof of component identity, the interacting containers must determine whether there is sufficient inter-container trust to accept the container-provided representations of component identity. In some environments, trust may simply be presumed; in others it may be evaluated more explicitly based on inter-container authentication and possibly the comparison of container identities to lists of trusted identities. If a required proof of identity is not provided, and when a sufficient inter-container trust relationship is absent, a container should reject or abandon a call.
Figure 9.2 illustrates these authentication concepts in two scenarios: an authenticated user scenario and an unauthenticated user scenario.
The authenticated user invokes a calling component that employs the user's authentication context to prove its identity to an intermediate component. When the called component makes a call, it propagates the identity of its caller. The propagated identity is unproven, so it will be accepted only if the targets trust the caller--that is, if they reside in the same protection domain.
The figure also differentiates identity propagation from delegation and subsequent impersonation. In propagation, the service providers bear the burden of determining whether they should accept propagated identities as authentic. In delegation, the user provides the called component with access to its authentication context, enabling the called component to impersonate the user in subsequent calls. Impersonation requires the user to trust the impersonator to act in its behalf.
The lower portion of the figure depicts the propagation of an unauthenticated user identity in the form of an anonymous credential. An anonymous credential is the one form of unproven identity that may be propagated independent of trust.
In a typical J2EE application, a user would employ a client container to interact with enterprise resources in the Web or EJB tiers. Resources available to the user may be protected or unprotected. Protected resources are distinguished by the presence of authorization rules (see Section 9.3 on page 293) that restrict access to some subset of non-anonymous identities. To access a protected resource, a user must present a non-anonymous credential such that its identity can be evaluated against the resource authorization policy. In the absence of a trust relationship between the client and resource containers, the credential must be accompanied by an authenticator that demonstrates the user's right to claim the identity as its own. This section describes the various authentication mechanisms supported by the J2EE platform and how to configure them.
9.2.2.1 Web Tier AuthenticationAn application component provider can designate that a collection of Web resources (Web components, HTML documents, image files, compressed archives, and so on) is protected by specifying an authorization constraint (described in Section 9.3.7.1 on page 299) for the collection. When an unauthenticated user tries to access a protected Web resource, the Web container will prompt the user to authenticate with the Web container. The request will not be accepted by the Web container until the user identity has been proven to the Web container and shown to be one of the identities granted permission to access the resource. Caller authentication performed on the first access to a protected resource is called lazy authentication.
When a user tries to access a protected Web-tier resource, the Web container activates the authentication mechanism defined in the application's deployment descriptor. J2EE Web containers must support three authentication mechanisms: HTTP basic authentication, form-based authentication, and HTTPS mutual authentication. In addition, they are encouraged to support HTTP digest authentication.
In basic authentication, the Web server authenticates a principal using the user name and password obtained from the Web client. In digest authentication a Web client authenticates to a Web server by sending the server a message digest along with its HTTP request message. The digest is computed by employing a one-way hash algorithm to a concatenation of the HTTP request message and the client's password. The digest is typically much smaller than the HTTP request and doesn't contain the password.
Form-based authentication lets developers customize the authentication user interface presented by an HTTP browser. Like HTTP basic authentication, form-based authentication is a relatively vulnerable authentication mechanism, since the content of the user dialog is sent as plain text and the target server is not authenticated.
In single-sign on environments, discretion must be exercised in customizing an application's authentication interface. It may be preferable to provide a single enterprise-wide custom user authentication interface rather than implementing a set of application-specific interfaces.
With mutual authentication, the client and server use X.509 certificates to establish their identity. Mutual authentication occurs over a channel protected by SSL. Hybrid mechanisms featuring either HTTP basic authentication, form-based authentication, or HTTP digest authentication over an SSL protected channel are also supported. SSL is used to protect the authenticators during network communication and to authenticate the server to the client such that authenticators are not exchanged with the wrong entities.
9.2.2.1.1 Authentication ConfigurationAn authentication mechanism is configured using the login-config element of the Web component deployment descriptor. Code Example 9.1, Code Example 9.2, and Code Example 9.3 illustrate the declarations of the authentication mechanisms required of J2EE Web containers.
<web-app> <login-config> <auth-method>BASIC</auth-method> <realm-name>jpets</realm-name> </login-config> </web-app>
| Code Example 9.1 HTTP Basic Authentication Configuration |
<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>
| Code Example 9.2 Form-Based Authentication Configuration |
<web-app> <login-config> <auth-method>CLIENT-CERT</auth-method> </login-config> </web-app>
| Code Example 9.3 Client Certificate Authentication Configuration |
9.2.2.1.2 Hybrid Authentication
In both HTTP basic and form-based authentication, passwords are not protected for confidentiality. This vulnerability can be overcome by running these authentication protocols over an SSL-protected session that ensures that all message content, including the client authenticators, are protected for confidentiality. Code Example 9.4 demonstrates how to configure HTTP basic authentication over SSL using the transport-guarantee element. Form-based authentication over SSL is configured in the same way.
<web-app> <security-constraint> ... <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> </web-app>
| Code Example 9.4 SSL Hybrid Authentication Mechanism |
9.2.2.1.3 Changing Authentication Identity
Sometimes users need to change authentication identities. This could happen when an authenticated user tries to visit a protected Web resource and is rebuffed for lack of access authority to the resource. Although the user can exit the browser and restart the authentication process, this is not always acceptable. Applications should give the user an opportunity to invalidate the authentication session and reauthenticate as a more appropriately privileged identity.
The error-page element may be used in the deployment descriptor of a Web application to configure a resource to be invoked by the Web container when the processing of an HTTP request produces a particular HTTP error code. This functionality may be employed to redirect an unauthorized request to a resource within the Web container that gives the user an opportunity to invalidate its authentication session. For example, the error-handling resource could return a form to the user containing the URI and parameters of the unauthorized request. The form would provide the user with an option to invalidate the current authentication session. Choosing to invalidate would cause the form containing the URI and parameters to be submitted to the Web container, where a session invalidation resource would be invoked. This resource would invalidate the current authentication session by calling HttpSession.invalidate. It then redirects the user, via the embedded URI and parameters, to the original unauthorized resource.
Prior to J2EE 1.3 and EJB 2.0, the J2EE platform did not require that EJB containers implement specific authentication mechanisms. Moreover, in many environments, network firewall technology prevents direct interaction (via RMI) between client containers and enterprise beans. As a result, it is common for an EJB container to rely on the authentication mechanisms and network accessibility of a Web container to vouch for the identity of users accessing enterprise beans via protected Web components. As illustrated in Figure 9.3, such configurations use the Web container to enforce protection domain boundaries for Web components and the enterprise beans that they call.
9.2.2.2.1 Common Secure Interoperability (CSIv2)
The J2EE 1.3 platform requires EJB containers and EJB client containers to support version 2 of the Common Secure Interoperability (CSIv2) protocol. CSIv2, a standard of the Object Management Group (OMG), defines a wire protocol for securing invocations made over RMI-IIOP. CSIv2 is designed to be used in environments where protecting the integrity or confidentiality of messages and authenticating servers to clients are enforced at the transport layer, perhaps by SSL or TLS. CSIv2 defines the Security Attribute Service (SAS) protocol that can be used above the transport to perform client authentication and impersonation where such functionality cannot be achieved using the underlying transport. The impersonation mechanism, called identity assertion, makes it possible for an intermediate to assert an identity other than its own, based on trust by the target in the intermediate. Identity assertion can be used by an intermediate J2EE container to propagate the identity of its callers in its calls. J2EE containers employ the CSIv2 identity assertion mechanism to establish the identities used by components to call other components as defined by application deployers. Figure 9.4 illustrates the CSIv2 architecture.
CSIv2 defines an annotation language for application servers to use to communicate security requirements to clients. Application servers use this language in their Interoperable Object References (IORs) so that their security requirements are available to inform the actions of their clients. A target's security requirements are conveyed as a mechanism definition for each CSIv2 layer. Each of these defines the combination of supported and required security functionality that must be satisfied by clients of the target. When a J2EE application is deployed on an application server, the deployer must define the CSIv2 security policy to be communicated to clients and enforced by the application server. The most notable aspects of this policy are whether the target requires an integrity and/or confidentiality protected transport, whether the target requires client authentication, and the mechanism or mechanisms required for client authentication.
9.2.2.3 Client Identity SelectionThe container of a J2EE server-side component establishes the invocation identity used when the component calls other J2EE components. The invocation identity established by the container depends on the identity selection policy defined by the deployer. A deployer may associate one of two identity selection policies with a component; use-caller-identity or runas(role-name). The use-caller-identity policy causes the container to use the identity of a component's caller in all calls made by the component. The runas(role-name) policy causes the container to use a static identity selected by the deployer from the principal identities mapped to the named security role.
Component identity selection policies may be defined for J2EE Web and EJB resources. Application developers who wish to hold component callers accountable for actions the components perform on their behalf should associate a use-caller-identity policy with the components. Use of the runas(role-name) identity selection policy breaks the chain of traceability and may be used to afford the caller with the privileges of the component. Code Example 9.5 depicts the configuration of client identity selection policies in an EJB deployment descriptor.
<enterprise-beans> <entity> <security-identity> <use-caller-identity/> </security-identity> ... </entity> <session> <security-identity> <run-as> <role-name> guest </role-name> </run-as> </security-identity> ... </session> ... </enterprise-beans>
| Code Example 9.5 Configuring EJB Identity Selection Policies |
Code Example 9.6 depicts the configuration of client identity selection policies in Web component deployment descriptors. In the absence of a run-as specification, the use-caller-identity policy is assumed.
<web-app> <servlet> <run-as> <role-name> guest </role-name> </run-as> ... </servlet> ... </web-app>
| Code Example 9.6 Configuring Identity Selection Policies for Web Components |
In integrating with enterprise information systems, J2EE components may use different security mechanisms and operate in different protection domains than the resources they access. In these cases, the calling container can be configured to manage the authentication to the resource for the calling component. This form of authentication is called container-managed resource manager sign on. The J2EE architecture also recognizes that some components require an ability to manage the specification of caller identity and the production of a suitable authenticator directly. For these applications, the J2EE architecture provides a means for an application component to engage in what is called application-managed resource manager sign on. Application-managed resource manager sign on is used when the ability to manipulate the authentication details is a fundamental aspect of the component's functionality.
The resource-ref elements of a component's deployment descriptor (described in greater detail in Section 9.2.4 on page 293) declare the resources used by the component. The value of the res-auth subelement declares whether sign on to the resource is managed by the container or application. Components that manage resource sign on can use the EJBContext.getCallerPrincipal or HttpServletRequest.getUserPrincipal methods to obtain the identity of their caller. A component can map the identity of its caller to a new identity and/or authentication secret as required by the target enterprise information system. With container-managed resource manager sign on, the container performs principal mapping on behalf of the component.
Care should be taken to ensure that access to any component that encapsulates or is provided by its container with a capability to sign on to another resource is secured by appropriate authorization rules (see Section 9.3.6 on page 297).
The Connector architecture discussed in Section 6.2.1 on page 177 offers a standard API for application-managed resource manager sign on. The Connector provided API will ensure portability of components that authenticate with enterprise information systems.
In a multitier, multicomponent application, certain call patterns should be avoided for usability reasons. For example, an application that calls protected EJB resources from unprotected Web resources can run into problems. This is because the Web tier's lazy authentication paradigm only provides users with an opportunity to authenticate when they attempt to access a protected resource. An unauthenticated user who attempts to visit an authentication-protected EJB resource from an unprotected Web resource will not be provided an opportunity to satisfy the authentication requirement of the EJB resource. One way to ensure that users of such applications can authenticate is to place protected Web resources in front of protected EJB components. Another approach is to include a link to a protected Web resource (perhaps appearing as an authenticate button) on Web resources that call protected EJB resources. This approach gives the user the option of authenticating by visiting a protected Web resource linked behind the button prior to accessing an EJB resource. This is especially useful where the user may have been denied access by the EJB container through an unprotected page.
Other call patterns should be avoided for security reasons. For example, when an application is deployed with a hybrid authentication mechanism, the deployer must ensure that the transport-guarantee element of each protected Web resource is set to CONFIDENTIAL. Otherwise, the client authenticator won't be fully protected. When form-based login is used over SSL, the transport-guarantee of the login page should be set to CONFIDENTIAL.
Some Web-based applications must authenticate users whose identities cannot be known in advance of their first use of the application. In contrast to typical computer user authentication environments, where a user must wait for an administrator to set up the user's account, such applications require an automated means for users to register an authentication identity for themselves. To self-register, the user is required to provide his or her identity and may be required to provide a password to protect the account along with one or more additional forms of identification, agree to some contractual obligations, and/or provide credit card information for payment. Once the registration dialog is complete, the user may authenticate as necessary to access the protected resources of the site.
The self-registration mechanisms provided by J2EE platforms are platform- specific. Applications that depend on these mechanisms should do so in a fashion that allows them to evolve, employing standard facilities and APIs as they are added to the platform. In the absence of portable self-registration mechanisms, application developers should resist the temptation to move user authentication and authorization into the application.
The application component provider is responsible for declaring references made by each component to other J2EE components and to external resources. These declarations are made in the deployment descriptor. In addition to their role in locating services, such declarations inform the deployer of all the places in the application where authentication may be necessary. Enterprise bean references are declared using ejb-ref elements. Enterprise information system references are declared with resource-ref elements. In both cases, the declarations are made in the scope of the calling component, and the collection of declared references serves to expose the application's inter-component/resource call tree.
J2EE platform deployment tools should present enterprise bean references to application deployers so that deployers know to secure interactions between the calling and called components. Deployers should use this knowledge to define CSIv2 security mechanism definitions that will appropriately secure the enterprise beans in all the ways that they are called. Deployers should use knowledge of the inter-container interactions that may occur as a result of the inter-component calls to configure appropriate inter-container security mechanisms and trust relationships.