IBM WebSphere Developer Technical Journal: Advanced authentication in WebSphere Application Server

Managing user authenticity and privileges in a distributed application server environment

The advanced authentication features in IBM® WebSphere® Application Server V6 support a more flexible authentication model with a new, highly customizable authentication framework that is based upon -- and extends -- Java™ Authentication and Authorization Service (JAAS).

Share:

Keys Botzum, Senior Technical Staff Member , IBM

Keys Botzum is a Senior Technical Staff Member with IBM Software Services for WebSphere. Mr. Botzum has over 10 years of experience in large scale distributed system design and additionally specializes in security. Mr. Botzum has worked with a variety of distributed technologies, including Sun RPC, DCE, CORBA, AFS, and DFS. Recently, he has been focusing on J2EE and related technologies. He holds a Masters degree in Computer Science from Stanford University and a B.S. in Applied Mathematics/Computer Science from Carnegie Mellon University. Mr. Botzum has published numerous papers on WebSphere and WebSphere security. Additional articles and presentations by Keys Botzum can be found at http://www.keysbotzum.com, as well as on IBM developerWorks WebSphere. He is also co-author of IBM WebSphere: Deployment and Advanced Configuration.



Bill Hines, Senior Certified Consulting IT Specialist , IBM

Bill Hines is a Senior Certified Consulting IT Specialist with IBM Software Services for WebSphere. His expertise includes installation, configuration, tuning, security, troubleshooting, and design/architecture of IBM WebSphere DataPower SOA Appliances. He is the co-author of the IBM Press book with John Rasmussen, Jaime Ryan, Simon Kapadia, and Jim Brennan, and the book with Keys Botzum, Tom Alcott, and Roland Barcia.


developerWorks Contributing author
        level

Paul Ilechko (paul.ilechko@us.ibm.com), Senior Solutions Architect, IBM

Paul Ilechko is a Senior Solutions Architect with IBM Software Services for WebSphere. Mr. Ilechko has over 25 years of experience in the IT Industry, including a background in both mainframe and distributed technologies. He has been involved with WebSphere and J2EE technology almost since their inception. His primary goal is to help IBM clients be successful with these products. Mr. Ilechko has a B.Sc. in Mathematics from the University of London.


developerWorks Contributing author
        level

Messaoud Benantar, Senior Software Engineer , IBM

Messaoud Benantar is a senior software engineer with IBM Software Services for WebSphere. He spent most of his career as a software developer working in IBM Large Systems Division, Software Group/Tivoli and IBM Global Services. His focus is on middleware and computing security.



Peter Birk, Senior Software Engineer, IBM

Peter Birk is a Senior Software Engineer for WebSphere Application Server Security Development. Mr. Birk has over 5 years of experience with the WebSphere Security Development team. Mr. Birk has worked on a variety of Security-related line items including the CSIv2 implementation for J2EE 1.4 compliance in WebSphere Application Server v5.0 and Security Attribute Propagation feature in WebSphere Application Server v5.1.1. He holds a Masters degree in Software Engineering from the University of Texas at Austin and a B.S. in Computer Engineering from the University of South Florida.



17 August 2005

From the IBM WebSphere Developer Technical Journal.

Introduction

In the past, IBM WebSphere Application Server had a rigid authentication model that made it challenging to support complex or unusual requirements. This situation was recently addressed with a new, highly customizable authentication framework based upon Java Authentication and Authorization Service (JAAS), extended with features that specifically address the requirements of managing user authenticity and privileges in a distributed application server environment.

This new framework defined for JAAS support in WebSphere Application Server includes:

  • well-defined interfaces for altering the user subject
  • enhanced Trusted Association Interceptor (TAI) support
  • explicit documentation for the WebSphere Application Server login process
  • the ability to assert complete user credentials to WebSphere Application Server (including group information)
  • replication of subjects in a distributed environment

plus a number of beneficial extensions to the security programming model.

This article will describe these new features in detail. The next sections provide some background on the fundamentals of the WebSphere Application Server authentication process and an overview of JAAS, then the remainder of the article will describe the most important aspects of these features as they relate to authentication.


Authentication overview

What version should you use?

The information in this article is based on WebSphere Application Server V6.0.1.2. The features described in this article first appeared in WebSphere Application Server V5.1.1 on the distributed platform, and are also available for WebSphere Application Server V5.1 on z/OS® as part of an update. However, since important fixes were applied in Version 6.0.1.2, we strongly recommend using that version.

First, let us look at the way in which WebSphere Application Server supports authentication:

  1. During a WebSphere Application Server login, some information has to be provided to prove the user's authenticity. This can be information like a user ID and password, an X509 certificate from an SSL session, or a single sign-on token from a browser.

  2. Once this information is either authenticated or validated (credentials are authenticated; tokens are validated), a JAAS subject is generated with a WebSphere Application Server credential and principal.

    • The WebSphere Application Server credential is a WSCredential implementation in the public credential set of the subject.
    • The WebSphere Application Server principal is a WSPrincipal implementation in the principal set of the subject.
  3. The custom types are, of course, created to contain custom information that WebSphere Application Server uses to track user identity.

  4. As resources are being accessed on the login thread, the subject is used in the server where the authentication took place to make authorization decisions.

Besides authentication, which requires a requesting entity to provide proof of its identity, WebSphere Application Server also supports identity assertion. This is a relaxed form of authentication that does not actually require proof of identity, but rather accepts the identity based on a trust relationship with the entity that vouches for the asserted identity.

Figure 1 illustrates the authentication methods available in WebSphere Application Server, in which we distinguish between two main authentication cases:

  • Web client authentication.
  • EJB client authentication.
Figure 1. WebSphere Application Server authentication methods
Figure 1. WebSphere Application Server authentication methods

Web authentication

Build security into applications by design

Secure workloads against the latest threats, simplify access control, and comply with regulatory requirements efficiently with Security services in IBM Bluemix.

Sign up for a free trial

The most common way for Web clients to authenticate is by providing a user ID and password, which can be accepted using either HTTP basic authentication or form-based authentication. WebSphere Application Server takes this information, looks up the user's unique ID (for example, a DN for LDAP) in the registry, and then verifies the password against the registry. In the case of LDAP, an ldap_bind is performed.

Web clients can also authenticate using client certificates. As with any SSL system, client certificate authentication is done at the termination of the SSL connection. Thus, the Web server -- rather than WebSphere Application Server -- is responsible for performing the client certificate authentication. When the certificate authentication is complete, the WebSphere Application Server Web server plug-in forwards the client certificate information to the application server, which then extracts information from the certificate and looks up the user in the registry (thus this is actually an identity assertion from the Web server to WebSphere Application Server). Be aware that when the Web server performs client certificate authentication, the Web server plug-in simply asserts that information from the Web server to the application server. Therefore, the connection from the Web server to the WebSphere Application Server should be protected by mutually authenticated SSL. Otherwise, any client with direct access to the application server Web container can easily forge certificate information and compromise security.

The information used for the registry lookup is customizable and can be made totally flexible if a custom registry is developed using the WebSphere Application Server custom registry interface. Once authentication has occurred, a single sign-on (SSO) token is created and sent back to the browser as a cookie -- this is equivalent to the LTPA token from prior releases of WebSphere Application Server -- and the security credential is cached by the security runtime.

EJB client authentication

EJB clients can authenticate using passwords or certificates. In the case of password-based authentication, the client runtime is responsible for obtaining the user ID and password and sending them to the server to be verified against the registry. In either case, if the authentication is determined to be valid, a CSIv2 session is established and is used for future requests. As with Web client authentication, a JAAS subject is created. Unlike Web clients, the subject is associated with the CSIv2 session rather than being placed in the security cache.

By default, the WebSphere Application Server client runtime prompts for user ID and password (if they are needed) using a graphical dialog box. This behavior can be controlled by editing the sas.client.props file, in which you can even specify a user ID and password. However, after obtaining the user ID and password it is recommended that clients use the JAAS login APIs to authenticate in some appropriate way under application control.

Trust association interceptor

HTTP clients can also pass identity information to WebSphere Application Server by using a trust association interceptor (TAI). The TAI interface provides a mechanism by which WebSphere Application Server enables an external component to authenticate the user and then assert the identity to the WebSphere Application Server Web container. You can develop a custom TAI or use one of several that are already commercially available. These TAIs are typically used in conjunction with a Web authentication proxy server, such as IBM's Tivoli® Access Manager or Netegrity's SiteMinder. These products authenticate the user and then simply inform WebSphere Application Server as to the end-user's identity. Typically this is done by the proxy server sending the user's ID and some additional verifiable information to the application server. The TAI extracts this information and then returns the user's ID (or optionally a subject) to WebSphere Application Server, which then queries the registry as it normally would, but does not validate the user's password. (If the user ID is not found in the registry, the assertion will, of course, fail.) This provides a powerful mechanism for enabling WebSphere Application Server to participate in a single sign-on domain.

Advanced TAIs can assert more than just the user's ID. In fact, they can assert an entire identity including all the group memberships required to support authorization. In such a case, WebSphere Application Server will not need to query the user registry.

Internal authentication

Application code, as well as WebSphere Application Server itself, can also authenticate from within the process, essentially creating an authenticated subject on-the-fly. To do this, the standard JAAS login APIs are used, following the same approach used in other scenarios: the provided user ID and password are validated against the registry, and if validation is successful, a JAAS subject and the authentication token are created. Though it may not be obvious, this implies that when WebSphere Application Server servers authenticate themselves, they use the same registry for authentication as user-level authentication.


JAAS overview

This section provides some basic introductory material on JAAS concepts, specifically the way in which login modules are used to provide pluggable authentication. Readers should become familiar with the JAAS specification.

Introduction to JAAS

WebSphere Application Server makes heavy use of the JAAS programming model. JAAS is a standard Java framework for performing a number of security related tasks, including login, custom authentication, and (through Java 2 extensions) authorization. WebSphere Application Server supports the use of JAAS for login and customized authentication (with the restrictions stated in this article). JAAS exposes an application-level programming interface (API) for use by applications, and a service programming interface (SPI) for the providers of its functionality. This model accomplishes the goal of insulating applications from service providers, thereby enabling portability across system platforms. Furthermore, JAAS follows the Pluggable Authentication Module (PAM) authentication model and so the service provider is completely pluggable through administrative configuration procedures.

Authentication sometimes involves more than one authentication system. To support this, JAAS is not only pluggable, but it is also stackable. This means a sequence of one or more mechanisms can be configured to drive the authentication process. Figure 2 is a high level representation of the JAAS model.

Figure 2. The JAAS authentication framework
Figure 2. The JAAS authentication framework

JAAS uses the concept of a subject to define a user. A subject is created at initial authentication time, and is really just a container for user information; it includes principal and credential data. Authentication is performed by login modules that are grouped into login configurations, providing the stackable authentication mechanism described above. Login modules have the ability to populate data into the subject. In WebSphere Application Server, this will include WSPrincipal and WSCredential objects. WSPrincipal is basically a Java principal, which is used to define an entity in Java such as a user, organization, or login ID. The WSCredential defines security information that will be used for authorization, such as group memberships.

JAAS control flow

As discussed above, the JAAS login process provides access to a series of login modules orchestrated into a login configuration. The JAAS invocation model consists of the caller (for example, a WebSphere Application Server container runtime) alternately calling JAAS components until all configured modules are invoked or a failure is encountered. Figure 3 shows this seesaw-like pattern of alternating control flow between the invoker and the JAAS modules.

Figure 3. The JAAS invocation model
Figure 3. The JAAS invocation model

The effect of each JAAS login module is driven by a configuration attribute with one of following values:

  • Required: The LoginModule is required to succeed. Irrespective of whether it succeeds or fails authentication still continues with the subsequent LoginModule list.

  • Requisite: The LoginModule is required to succeed. If it succeeds, authentication continues down the LoginModule list. If it fails, control immediately returns to the application (authentication does not proceed down the LoginModule list).

  • Sufficient: The LoginModule is not required to succeed. If it does succeed, control immediately returns to the application (authentication does not proceed down the LoginModule list). If it fails, authentication continues down the LoginModule list.

  • Optional: The LoginModule is not required to succeed. If it succeeds or fails, authentication still continues to proceed down the LoginModule list.

(By default, WebSphere Application Server login modules have a required semantic.)

We will now expand on the flow of Figure 3, by showing the calling sequence for JAAS modules and then discuss the data constructs exchanged via the controller/invoker. This will involve manipulation of the core JAAS objects, which are:

  • Subject
  • LoginContext
  • LoginModule

The Subject and the LoginContext objects are visible to the JAAS invoker while the LoginModule is not; that is, it is subject to configuration only. To authenticate an entity (which we will call the subject) the following steps are performed:

  1. An application instantiates a LoginContext.

  2. The LoginContext consults a login configuration to load all of the login modules that are part of that configuration.

  3. The application invokes the LoginContext's login method.

  4. The login method invokes the loaded login modules in accordance with the semantics mentioned above. Each login module attempts to authenticate the subject. Upon success, login modules associate relevant principals and credentials with a Subject object that represents the subject being authenticated.

  5. The LoginContext returns the authentication status to the application.

  6. Upon success, the application retrieves the subject from the LoginContext.

Refer to the JAAS Reference Guide for detailed constructor and method signatures of the Subject, LoginContext, and LoginModule classes.

Data flow across login module invocations

As described above, authentication of the subject in the JAAS programming model is performed by instantiating a separate LoginContext object and its corresponding LoginModule objects. These two constructs encapsulate authentication data for the subject being authenticated.

Before each login module is invoked, it is initialized with the subject, a shared login module state, login module-specific options, and possibly a CallbackHandler. Upon successful authentication, the subject is updated with relevant credentials. Data encapsulated by the subject therefore represents the first construct passed across configured login modules, while the shared state represents the second such data element. These two objects allow for the effect of one login module to become visible to the next module in the list.

The optional CallbackHandler is used by the login module to gather authentication information about the environment and the user, including an identity and a proof of possession of that identity. It is possible for this process to involve an interaction with the end user; however, this is not feasible for server side callbacks. On the server side, this information is obtained from an incoming client request or from the environment itself. Callback handlers for WebSphere Application Server are discussed in the JAAS usage section.


Authentication plug points

The WebSphere Application Server authentication process is fully pluggable. By providing plug points for custom code at most key steps, it is possible to heavily customize the WebSphere Application Server authentication process. Code can be developed to add custom information to a subject, require additional authentication information as part of a login process, or even bypass the normal registry usage by asserting complete user credentials to WebSphere Application Server.

There are two ways in which these extensions to the WebSphere Application Server authentication model may be achieved:

  • First, most of the authentication process is built around JAAS login modules, and so it is possible to plug in custom login modules before, after, or between the login modules provided by IBM (however, the IBM modules must not be removed).

  • Second, the TAI interface enables the assertion of complete credentials for Web-based authentication.

WebSphere Application Server provides a set of standard login configurations with login modules and callbacks that are used in various situations to achieve authentication. These modules and callback handlers are defined and available depending on the specific authentication situation. The major configurations that will support most needs are for Web inbound, RMI inbound, and RMI outbound scenarios. We will discuss each in some detail, but first we will look at the standard WebSphere Application Server login modules.

Standard login modules

Of interest to us here are three login modules which are pre-defined in WebSphere Application Server for use with WEB_INBOUND, RMI_INBOUND, DEFAULT, and RMI_OUTBOUND configurations:

  • com.ibm.ws.security.server.lm.ltpaLoginModule
    Creates credentials, either using a user-provided hashtable or default registry access.

  • com.ibm.ws.security.server.lm.wsMapDefaultInboundLoginModule
    Instantiates a subject, using either credentials or tokens, depending on login type.

  • com.ibm.ws.security.server.lm.wsMapCSIv2OutboundLoginModule
    Converts subject into tokens for outbound transmission over IIOP; this is used only in RMI_OUTBOUND.

You can place your custom login modules either before or after the IBM login modules; where you put them will depend on what you are trying to achieve:

  • If you are looking to assert identity information and bypass the standard WebSphere Application Server login module behavior of authenticating against a user registry, then you must place your login module before the ltpaLoginModule.

  • However, if your login module needs to use information created by the WebSphere Application Server login modules (for example, you need to see the authenticated user to add extra information to the subject), then you would place your login module after the IBM modules.

It is also possible to place your custom module between the two IBM login modules, but that is rarely required. One such case may be if you write an RMI_OUTBOUND login module, when it would be crucial that your login module execute before the IBM wsMapCSIv2OutboundLoginModule.

System login configurations

WebSphere Application Server now defines four system login configurations that are used in specific situations related to security:

  • WEB_INBOUND
  • RMI_INBOUND
  • RMI_OUTBOUND
  • DEFAULT.

(There are also application login configurations that are used for other purposes, such as J2EE Connector authentication, which will not be discussed here.)

WEB_INBOUND

Figure 4 shows a simplified view of the authentication flow for the WEB_INBOUND configuration.

Figure 4. Web inbound flow
Figure 4. Web inbound flow

As its name implies, this configuration is intended to be used to authenticate Web-based (HTTP) traffic. There are three basic scenarios:

  • If a user has already authenticated (meaning an SSO token is present in the request) and the subject is available in the local security cache, then the TAI and all login modules are bypassed and control is passed directly into the Web container.

  • If an SSO token is available but the subject is not in the local security cache, WebSphere Application Server will attempt to obtain the user's subject from another server (we will explain how later). If this succeeds, then what is called a propagation login is performed. (Propagation is discussed in a later section.) The login modules will be called and are expected to validate the subject. If WebSphere Application Server is unable to obtain the subject, then things get tricky. By default, WebSphere Application Server will perform an initial login (in the next bullet item), but this behavior can be altered.

  • If no SSO token is available, then an initial login is performed. First, the TAI will be invoked if it exists. After the TAI is invoked, the login modules will be invoked. The TAI can create a subject for use by the login modules.

When the login modules are invoked, both the required login modules and any custom login modules will be invoked. The sequence in which they are invoked is determined administratively via the login configuration. Of course, you can decide to write a custom TAI and custom login modules, but this is unlikely to be a desirable option.

As you look at the Figure 4, notice that the TAI can provide a custom subject to the login modules; custom login modules can also customize the subject. Shortly, we will go into more detail about what login modules and the TAI can do.

RMI_INBOUND

Figure 5 shows a simplified view of the authentication flow in the RMI_INBOUND configuration.

Figure 5. RMI inbound flow
Figure 5. RMI inbound flow

As its name implies, this configuration is intended to be used to authenticate RMI/IIOP requests; that is, requests that bypass the Web container and invoke an EJB directly. These could be requests from a standalone EJB client or from another application server.

There are three basic scenarios:

  • If a user has already been authenticated, and a thus a CSIv2 session has been established, all login modules are bypassed and control is passed directly into the EJB container.

  • If the user already has an authenticated context at the caller, the stack of login modules in the configuration will be executed in a propagation login (the difference between an initial login and a propagation login will be explained later) as the user authentication data (known as tokens) are propagated from one server to the next. Both the required WebSphere Application Server login modules, as well as any custom login modules added to the configuration, will be invoked.

  • If the user has not authenticated, the login modules will be invoked just as before, but this time in an initial login mode. The login modules are responsible for verifying the user's authentication data and creating the subject.

RMI_OUTBOUND

Figure 6 shows how the authentication flow occurs in the RMI_OUTBOUND configuration.

Figure 6. RMI outbound flow
Figure 6. RMI outbound flow

As its name implies, this configuration is intended to be used for special authentication-related processing on a call out to a remote EJB container, which typically involves some type of credential mapping processing. You can perform identity assertion to a remote server without the need for a login module, but if the remote server does not share a registry with the authenticating server, you may need to use a login module to map the existing user identity information to a credential that is valid for that server.

  • If a CSIv2 session is already in place, the remote container is called directly and the login modules are not executed.

  • Otherwise, the stack of login modules in the configuration will be executed. This will include both the required WebSphere Application Server login module, as well as any custom login modules added to the configuration.

This configuration will not be discussed further in this paper.

Other configurations

There are other defined login configurations in WebSphere Application Server. The DEFAULT login configuration handles situations when none of the above configurations apply; these include SOAP requests from the admin client and JMX admin authentication requests. There might also be legacy login configurations, such as SWAM, LTPA and LTPA_WEB. However, these should no longer be used as of WebSphere Application Server V5.1.1.

Additionally, there are two login configurations related to Web services, wssecurity.signature and wssecurity.IDAssertion, which this paper will not cover.


TAI usage

With an understanding of JAAS and the basics of WebSphere Application Server authentication, we will now discuss how to customize the WebSphere Application Server authentication process in more detail. We will begin with custom TAIs, since these are the easiest to understand and use -- and are also the most commonly used since TAIs support Web-based single sign-on.

TAI: Asserting identity information to WebSphere Application Server

If the user has already been authenticated by some authentication system other than WebSphere Application Server, it is possible to inform WebSphere Application Server of the user's identity information rather than requiring that the user re-authenticate. This is known as identity assertion.

WebSphere Application Server has long supported Web-based identity assertion as part of the TAI interface. As of WebSphere Application Server V5.1.1 there are two TAI interfaces. The legacy TAI method of returning the user ID to WebSphere Application Server is retained, but a new, more powerful method is now available. Custom developed code can assert not just the user's ID but rather the entire user identity (user ID, unique ID, and group information). If this is done, WebSphere Application Server will not contact the UserRegistry to derive additional user information. This may improve performance in situations where the user's group information is already known, but more importantly, this gives applications the flexibility to determine a user's group memberships by criteria other than the static information in the UserRegistry. An additional new feature in the TAI is the support for a multi-phase negotiation process, which enables the TAI to request additional information from the client which is asserting identity.

The advanced TAI interface that supports Subject assertion is com.ibm.wsspi.security.tai.TrustAssociationInterceptor. Note that this is different from the older (and still supported) com.ibm.websphere.security.TrustAssociationInterceptor.

As mentioned above, this advanced TAI interface supports a multi-phase negotiated authentication process (for example, some systems require a challenge response protocol back to the client). The two key methods in this new interface are:

  • public boolean isTargetInterceptor(HttpServletRequest req)
    This method will return true if this TAI should handle this request; false tells WebSphere Application Server to ignore this TAI.

  • public TAIResult negotiateValidateandEstablishTrust(HttpServletRequest req, HttpServletResponse res)
    This method returns a TAIResult object which indicates the status of the request that is being processed. The HTTP response object can be modified if needed.

The TAIResult class has three static methods for creating a TAIResult, all of which always take an int as the first parameter. This parameter is expected to be a valid HTTP request return code and is interpreted in one of two ways:

  • The value HttpServletResponse.SC_OK tells WebSphere Application Server that the TAI has completed its negotiation. WebSphere Application Server will then use the information in the TAIResult to create a user identity.

  • Any other value indicates that WebSphere Application Server should return the TAI output (which has been placed into the HttpServletResponse) and return it to the Web client (or more likely, to an authenticating proxy). Typically, this will result in the Web client providing additional information on a future request and making another call to the TAI.

The created TAIResults have the following meanings:

  • public static TAIResult create(int status);
    Indicates only a status to WebSphere Application Server. The status should not be SC_OK since no identity information is provided. This will typically be used to inform the asserting client that the TAI needs additional information. Most likely, the TAI has modified the HttpServletResponse object to send some useful information back to the caller.

  • public static TAIResult create(int status, String principal);
    Indicates a status and the user ID or unique ID for this user. WebSphere Application Server will create credentials by querying the registry for all required user information. Status must be SC_OK.

  • public static TAIResult create(int status, String principal, Subject subject);
    Indicates a status, the user ID or unique ID for this user, and a custom subject. If the subject contains a complete user hashtable (see the next section on creating a custom subject), the principal will be ignored. The contents of the subject will become part of the eventual user subject. Status must be SC_OK.

There are a few additional methods on the TrustAssociationInterceptor interface which are discussed in the Java documentation. These are used for initialization, shutdown, and for identifying the TAI to WebSphere Application Server.

Given this framework, a custom TAI can accomplish a number of different things. A number of simple examples follow, with a more complete example to be presented later. For clarity, most of these examples do not show error handling.

TAI that asserts a user simply

Here is a trivial example of a negotiateValidateandEstablishTrust that asserts a user ID:

Listing 1
TAIResult negotiateValidateandEstablishTrust
	(HTTPServletRequest req, HTTPServletResponse response) {

	String userid = //get from request somehow
	if ( didn't work )
		throw new WebTrustAssociationFailedException("a reason why");
	return TAIResult.create(HTTPServletResponse.SC_OK, userid);
}

In this case, only the user's user ID is provided. WebSphere Application Server will access the registry to retrieve all additional user information, such as group memberships.

To indicate authentication failure (and to cause WebSphere Application Server to fail the user authentication) you must throw a WebTrustAssociationFailedException.

TAI that negotiates

This example shows how to indicate that additional negotiation is required, and also how to return a user ID:

Listing 2
TAIResult negotiateValidateandEstablishTrust
	(HTTPServletRequest req, HTTPServletResponse response) {

	//determines phase by examining request
	if (phase one) {
		... Alter response object appropriately...

		//Indicate not done to WebSphere Application Server. 
		//Return code is client specific
		return TAIResult.create (HTTPServletResponse.SC_CONTINUE);
	} else {///done
		String userid = //get from request somehow
		return TAIResult.create(HTTPServletResponse.SC_OK, userid);
	}
}

Create a custom subject

WebSphere Application Server also provides the ability to create a custom subject. This can actually be achieved by user code either in the TAI or in a custom login module. Before we get into the details of how this is achieved in a TAI, we need to clarify that there are actually two very distinct things that can be described as "creating a custom Subject." The simpler meaning is merely the adding of custom attributes to a standard subject, created by WebSphere Application Server using its normal method.

One important thing to remember is that if you create custom subjects containing custom attributes, the code to create that subject probably needs to be on every application server. This is because any application server might create the subject as part of an authentication. More importantly, every application server potentially needs to deserialize the subject, and so in order for it to make sense, it has to have access to the subject's Java class definitions. If the target server does not have the custom classes, deserialization will fail and WebSphere Application Server will simply discard the custom information.

The second meaning of "custom subject" is the creation of a subject with custom credentials by providing a custom hashtable that contains user identity information. In this scenario, user code provides all of the identity information required by WebSphere Application Server to generate a subject.

With either type of custom subject, it is important to understand the implications in a clustered environment. This will be covered in detail later in the sections on JAAS usage and propagation, but the important thing to be aware of is that if the subject you create is modified in such a way that WebSphere Application Server cannot recreate it using its own default mechanisms, then you must add a custom cache key to the subject. This key is used during identity propagation to ensure that the correct subject is instantiated on another application server. This is equally true whether you create a custom subject with custom credentials, or merely add attributes to the standard subject created by WebSphere Application Server.

  • Add information to a subject

    The code below shows how to add custom attributes to a subject. WebSphere Application Server will still create a normal user credential, accessing the user registry as required, but will retain the custom attribute in the subject for future application use during this login session. The custom attribute in the example is added to the public credentials area of the subject (which is probably where you would normally add it). (For this to work in a distributed environment, the SomeType class must be serializable.)

    Listing 3
    TAIResult negotiateValidateandEstablishTrust
    	(HTTPServletRequest req, HTTPServletRespose response) {
    
    	String userid = // get from request somehow
    
    	SomeType somethingextra = new SomeType();
    	... do whatever to somethingextra ...
    Subject subject = new Subject();
    Subject.getPublicCredentials().add(somethingextra);
    
    return TAIResult.create(HTTPServletResponse.SC_OK, userid, subject);
    }
  • Create a custom subject with custom credentials

    If you want to completely override the authentication process and complete a full custom subject with all required credentials, a hashtable of authentication data must be created and added to the subject, as in this sample code:

    Listing 4
    String userid = //get from request
    InitialContext ctx = new InitialContext();
    UserRegistry reg  =(UserRegistry)ctx.lookup("UserRegistry");
    String uniqueid = reg.getUniqueUserID(userid);
    
    //define groups
    ArrayList groups = new ArrayList();
    // add admin group 
    groups.add(reg.getUniqueGroupId("Administrators"));
    
    // stash in hashtable
    Hashtable hashtable = new Hashtable();
    hashtable.put(AttributeNameConstants.WSCREDENTIAL_UNIQUEID,uniqueid);
    hashtable.put(AttributeNameConstants.WSCREDENTIAL_SECURITYNAME,userid);
    hashtable.put(AttributeNameConstants.WSCREDENTIAL_GROUPS,groups);
    hashtable.put(AttributeNameConstants.WSCREDENTIAL_CACHE_KEY,uniqueid+"MyCustom");
    
    Subject subject = new Subject();
    subject. getPublicCredentials().add(hashtable);
    return TAIResult.create(HTTPServletResponse.SC_OK, "ignored", subject);

    In this example, we create our own custom array of groups for the user, containing the single element "Administrators". We add this to the hashtable of information for the user, which you can see we also update with the user ID and unique ID (obtained from the user registry). We also create a custom cache key to ensure that the subject will be recreated correctly on propagation.

    As you can see from the sample above, WebSphere Application Server will expect to find specific key information in the hashtable in the subject. The keys are defined in com.ibm.wsspi.security.token.AttributeNameConstants and they are used as follows:

    • Key: WSCREDENTIAL_UNIQUEID
      Description: This should be a unique representation of the user. The best way to obtain a unique ID for a user is to call the WebSphere Application Server UserRegistry method: public String getUniqueUserId(String userSecurityName). This will also ensure compatibility with the WebSphere Application Server default implementation for the unique ID. If you need to customize the unique ID for some reason, the best way would be to write a Custom User Registry that was able to generate meaningful and appropriately unique IDs.
      Format: this is a java.lang.String.
      Expected format examples (realm/uniqueUserId):
      LDAP: "ldaphost.austin.ibm.com:389/cn=user,o=ibm,c=us"
      Windows: "MYWINHOST/S-1-5-21-963918322-163748893-4247568029-500"
      UNIX: "MYUNIXHOST/32"

    • Key: WSCREDENTIAL_SECURITYNAME
      Description: This is the securityName (commonly called the user ID or short name) of the authenticated user. (WebSphere Application Server uses the securityName attribute for the getRemoteUser(), getUserPrincipal() and getCallerPrincipal() APIs.) The best way to ensure compatibility with the WebSphere Application Server default implementation for the securityName value is to call the WebSphere Application Server UserRegistry method: public String getUserSecurityName(String uniqueUserId).
      Format: this is a java.lang.String.
      Expected format examples:
      LDAP: "user" (ldap UID)
      Windows: "user" (Windows username)
      UNIX: "user" (UNIX username)

    • Key: WSCREDENTIAL_GROUPS
      Description: This is an ArrayList of realm qualified groups to which this user belongs. The format of these groups is important as they are used by the WebSphere Application Server authorization engine for group-to-role mapping in the deployment descriptor. The format provided must match what the WebSphere Application Server default implementation expects. If you use a third party authorization provider, then this should be whatever the third party provider expects. The best way to ensure compatibility with the WebSphere Application Server default implementation for the unique group ID value is to call the WebSphere Application Server UserRegistry method: public List getUniqueGroupIds(String uniqueUserId). If the HashMap is present in the subject created by the TAI but it contains no groups, then WebSphere Application Server will create a credential with the user having no groups; it will not query the registry to obtain group information in this scenario.
      Format: this is a java.util.ArrayList of java.lang.String.
      Expected format examples for each group in the ArrayList:
      LDAP: "ldap1.austin.ibm.com:389/cn=group1,o=ibm,c=us"
      Windows: "MYWINREALM/S-1-5-32-544"
      UNIX: "MY/S-1-5-32-544"

    In addition to the three keys listed above, you may also need to specify a fourth key, the cache key, which is a unique identifier further defining the uniqueness of these credentials. The cache key defines how WebSphere Application Server internally caches subject information. However, it is important to understand that if you let WebSphere Application Server use the default cache key, it will recreate a default subject as needed, which means that customization of the subject could be lost.

    This point is crucial. If you are providing only information that could also be directly derived from the UserRegistry, there is no need to provide the unique cache key. WebSphere Application Server will cache the information provided using the user's unique ID, and if the information must be recreated, then WebSphere Application Server will simply query the registry. However, if the information you are providing is not derivable from the UserRegistry, or is perhaps unique to this particular authentication session, then a unique cache key must be provided. The key must be appropriately unique; that is, it must at least be globally unique across all users. For example, if the subject will always contain the same information for the same user, the user's unique ID plus a simple hard coded constant value is sufficient (as we've done in our example above). On the other hand, if the information in the subject is unique to this specific login session (perhaps it contains the login time or login source), then the cache key must be dynamically generated (again including the user's unique ID) and should be unique across all users and instances of your custom login module or TAI. The cache key definition is:

    • Key: WSCREDENTIAL_CACHE_KEY
      Format: this is a java.lang.String

TAI scenario and example

The following code shows an example TAI that incorporates some of the concepts that we have discussed so far. This TAI accepts three parameters, previously set by an unsecured Web login application: the user ID and password of the requestor, plus a flag called AdminPriv, which enables a user who would normally be given administrator privileges (that is, they are a member of the admin registry group) to either accept or decline those privileges. This is a somewhat unrealistic example, but it serves the purpose of showing how to override registry attributes by creating a custom subject.

The TAI will verify the user's password using the UserRegistry, obtain the user's groups, and also verify that the user is actually a member of the admin group if they request admin privileges. If the user does not request admin access and the user is a member of the admin group, the TAI will remove that group from the group list and pass it to WebSphere Application Server. In this case, a custom key must be created because we have modified the subject based on some dynamic, non-registry driven information (in this case the user's preference to be admin or not for this particular session). In all other cases, the TAI will just use the default group list from the user's registry entry, so a custom cache key is not needed (the subject will contain only default information).

TAI installation and configuration

As discussed earlier, to develop a custom TAI you need to implement the TrustAssociationInterceptor interface defined in the com.ibm.wsspi.security.tai package. The WebSphere Application Server library in which this interface is defined is in the JAR file wssec.jar. The implementing JAR file that contains your custom TAI (we have provided loginexamples.jar for this purpose) should be deployed in the WebSphere Application Server environment in a location that is accessible by the security portions of the application server runtime. Your custom TAI implementation should be deployed under the WAS-INSTALL/lib/ext directory for the application server nodes because the entire WebSphere Application Server runtime can access code here. You may encounter problems if you try to place your TAI under a shared library for just the application server.

Assuming that you have enabled Global Security for your server, follow these steps to make sure you properly configure your custom TAI:

  1. Install your TAI JAR in WAS-INSTALL/lib/ext. For our example, we simply copied the loginexamples.jar file to this directory for our WebSphere Application Server V6 install.

  2. From the WebSphere Application Server administrative console, navigate to Security => Global Security and ensure that the Active authentication mechanism dropdown is set to Lightweight Third Party Authentication (LTPA) (Figure 7).

    Figure 7. Global Security Enabled with LTPA
    Figure 7. Global Security Enabled with LTPA
  3. Verify that LTPA is configured for use on your server by selecting Security => Global security => Authentication mechanisms => LTPA and you should see the Password attribute already filled in.

  4. Select Security => Global security => Authentication mechanisms => LTPA => Trust association and check the Trust Association Enabled box, then Apply.

  5. Select Security => Global security => Authentication mechanisms => LTPA => Trust association => Interceptors. Click on New. Enter the fully qualified classname to your custom TAI class, then Apply. (Figure 8)

    Figure 8. Our example TAI configuration
    Figure 8. Our example TAI configuration
  6. Our sample TAI does not depend on any custom properties. However, if yours does, then select Security => Global Security => Authentication Mechanisms => LTPA => Trust Association => Interceptors => yourTAIclass => Custom Properties => New to enter the (key, value) pairs for the properties on which yourTAI depends, then Apply.

  7. Save your configuration and then restart your server to make your TAI fully operational.

Running the sample TAI

After you complete the TAI configuration and install the TAITestEAR.ear file (which consists of a single WAR file that contains a login JSP and a Servlet called PrintUserInfo), open a browser and navigate to the login.jsp page, as shown in Figure 9.

Figure 9. Example login page
Figure 9. Example login page

Our example behaves as follows:

  • Case 1

    If we log in with a user that has administrative privileges (that is, the user is a member of the admin group in the user registry), and that user checks the box stating that they desire to log in with those privileges, the following code in our TAI is executed:

    Listing 5
    //determine if user wants to be admin.
    String adminPriv = req.getParameter("AdminPriv");
    if (adminPriv != null && adminPriv.equals("Y")) {
    	System.out.println("User desires admin");
    	wantsAdmin = true;
    }
    
    //go through groups and remove admin group if needed.
    Iterator iter = groups.iterator();
    boolean foundAdmin = false;
    while (iter.hasNext()) {
    	String gid = (String) iter.next();
    	if (gid.equals("admin")) {
    		foundAdmin = true;
    		if (wantsAdmin == false) {
    			iter.remove();
    			customGroups = true;
    		}
    		break;
    	}
    }
    
    //Now, a quick error check (wanting admin when not an admin)
    if ((!foundAdmin) && wantsAdmin) {
    	... Error code not shown ...
    }
    
    String key;
    if (customGroups) {
    	key = uniqueid + "ExampleTAIAdminRemoved";
    } else {
    	key = uniqueid;
    }
    
    Subject subject = createSubject(userid, uniqueid,
    	convertGroupsToUniqueIds(reg, groups), key);
    return TAIResult.create(HttpServletResponse.SC_OK, "notused", subject);

    The full source code with all details is available in the included download file, but as you can see, we test whether the user wants to be an administrator and then check to see if they are in the admin group. If the user wants to be an administrator and is in the admin group, we leave the group list untouched.

    In this case, the user's group list is unaltered, since the user is in the admin group and wants to be in that group. After determining the group list, we create a subject and return it to WebSphere Application Server using TAIResult. The resulting output from the PrintUserInfo servlet is shown in Figure 10.

    Figure 10. Admin user logged in with admin privileges
    Figure 10. Admin user logged in with admin privileges

    Figure 10 shows that the user's subject contains the unique group ID customRealm/987, which corresponds to the admin group in our registry. This is essentially the subject as WebSphere Application Server would have created it.

  • Case 2

    Now, let's do this again -- this time customizing the groups -- and see how it is different.

    Close the browser to destroy the user's credential, reopen a new browser and log in again with the same user. If we uncheck the administrative privileges box (indicating this user does not wish to log in with admin privileges), the code previously shown is executed. In this case, however, the wantsAdmin variable is set to false. As a result, the admin group will be removed from the group list. This also means that the customGroups Boolean will be set to true. As a result, we will create a slightly different custom cache key to ensure that the two subjects are distinct.

    The output for this case is shown in Figure 11. Notice that the user still has the admin group defined in the user registry, but we have removed it from the custom subject.

    Figure 11. User's custom subject information with admin group removed
    Figure 11. User's custom subject information with admin group removed

You can observe other use cases by reviewing the sample code in the download file, such as the case where a user who does not belong to the admin group asks for admin privileges. The sample also checks the user's password, even though this is something you might not typically do in a real TAI, as its purpose, after all, is to trust (the T in TAI!) the front end authenticator.

Now, let's look at a really interesting situation regarding our last example. Since we are using a subject that contains custom group information in the scenario with the admin group removed, what would happen if our subject has to be recreated later? We discussed this possibility in the cache key section earlier. To show how important this is, we will create a scenario and see what happens if we had not used our custom cache key. Here is the code we use for creating the subject:

Listing 6
private Subject createSubject(String userid, String uniqueid, List groups,
			String key) {
	Subject subject = new Subject();
	Hashtable hashtable = new Hashtable();
	hashtable.put(AttributeNameConstants.WSCREDENTIAL_UNIQUEID, uniqueid);
	hashtable.put(AttributeNameConstants.WSCREDENTIAL_SECURITYNAME, userid);
	hashtable.put(AttributeNameConstants.WSCREDENTIAL_GROUPS, groups);
	System.out.println("Subject cache key is " + key);
	hashtable.put(AttributeNameConstants.WSCREDENTIAL_CACHE_KEY, key);
	subject.getPublicCredentials().add(hashtable);

	return subject;
}

Go ahead and comment out the line of code out that sets the cache key, rebuild it, and then update the TAI JAR file. Once that is done, follow these steps:

  1. Start two application servers (non-clustered) in the same cell, with both running our sample application. Server1 is listening on port 9443 and server2 is listening on port 9444.

  2. We will run the application's login.jsp from server1 and login with a member of the admin group, leaving the administrative privileges box unchecked. This will execute the section of code that creates the custom subject (by removing the admin group from the user's subject).

  3. This will display the page shown in Figure 11: our admin user with the admin group stripped from the custom subject. This custom subject has been cached on server1, and the LTPA token has been created and sent to the user's browser. So far, so good.

  4. Now, stop server1 and simply modify the URL in the browser's address window so that the port is changed from server1's 9443 to server2's 9444, then press Enter. This sends the request to the instance of our application that has thus far been idling unused on server2. What we see now is shown in Figure 12. Notice that the admin group has reappeared in the user's subject! In a real-life scenario, this change would likely be much more subtle and difficult to detect.

Figure 12. The subject information has been incorrectly recreated at server2
Figure 12. The subject information has been incorrectly recreated at server2

Let us review what has happened behind the scenes. We ran this scenario with the powerful WebSphere Application Server trace facility on (we used com.ibm.ws.security.* and com.ibm.websphere.security.*), so we will show a few snippets for better understanding.

  • When the request came in to server2, WebSphere Application Server realized that the URI was protected:

    [5/11/05 14:41:12:598 EDT] 0000003a WebCollaborat 3   URI -  /PrintUserInfo.GET is 
    protected
  • WebSphere Application Server sees the LTPA cookie in the request header and tries to retrieve the corresponding subject from its own security cache. Since this was in server1, it is not found.

  • Next, WebSphere Application Server tries to use DynaCache to retrieve the subject:

       [5/11/05 14:41:12:649 EDT] 0000003a AuthCache     <  getSubject(token) 
    subject=null Exit
       [5/11/05 14:41:12:649 EDT] 0000003a distContextMa >  
    getOpaqueTokenFromCacheOrOriginatingServer Entry
       [5/11/05 14:41:12:649 EDT] 0000003a distContextMa 3   Getting distributed object 
    from DynaCache.
  • The subject is not found in DynaCache, so WebSphere Application Server next attempts to get the subject from the original server via an MBean:

       [5/11/05 14:41:12:719 EDT] 0000003a WSCredentialT <  
    getDistributedObjectNotShared (null) Exit
       [5/11/05 14:41:12:719 EDT] 0000003a distContextMa 3   Not found in DynaCache, 
    getting distributed object using MBean.
  • To determine where the originating server is, WebSphere Application Server decrypts the LTPA token, which has the server name and SOAP admin port:

    [5/11/05 14:41:12:759 EDT] 0000003a LTPAToken2    3   tokenString after decrypt: 
    expire:1115844008917$host:billhinest40.hines.ibm.com$java.naming.provider.url:corb
    aloc\:iiop\:billhinest40.hines.ibm.com\:9810/WsnAdminNameService$port:8878$process
    .serverName:HinesCell01\:Node01\:server1$security.authMechOID:oid\:1.3.18.0.2.30.2
    $type:SOAP$u:user\:customRealm/456%1115844008947%fwJYbzUveypeYKWrjjzlZqfhfqHyXwoUa
    pknRpoV2FfyMoQcU2hHBGBaU4C648tr40vySBdFJ2SXYN0MFkOWVVS80nywQYiqEE9Bm2JsezPjTDKWWgy
    S8vnBpq6YobrNdlf5uTlOFREZHAo8cv4w47fJRNoE9ohZkS26t4lrGog=
  • Of course, the attempt fails, as server1 is now down:

    [5/11/05 14:41:14:782 EDT] 0000003a WSCredentialT 3   Exception occurred getting
     admin client connection.
        com.ibm.websphere.management.exception.ConnectorException: ADMC0016E: The 
    system cannot create a SOAP connector to connect to host 
    billhinest40.hines.ibm.com at port 8878.
  • WebSphere Application Server will now try to recreate the user's subject using token information:

    [5/11/05 14:41:14:822 EDT] 0000003a ltpaLoginModu 3   Using credential token for 
    authentication
    [5/11/05 14:41:14:822 EDT] 0000003a ltpaLoginModu 3   Converting SSO token to 
    authentication token.
    [5/11/05 14:41:14:822 EDT] 0000003a LTPAServerObj >  validateToken Entry
    [5/11/05 14:41:14:822 EDT] 0000003a LTPAServerObj <  BEGIN VALIDATING TOKEN: some 
    errors may occur, look for SUCCESS: Exit
  • Without the presence of the custom cache key, WebSphere Application Server recreates the subject by querying the registry to find the user's ID and group associations. This results in a problem that must be clearly understood: the user's credentials have been changed by accident. The user opted to not have admin privileges when they logged in, and now they have the privileges. This should not be allowed to occur.

This is a trivial example, but as you might imagine there are situations where this kind of behavior could be intolerable.

Let's run the same test again (the user again leaves the administrative privileges box unchecked), but this time with the custom cache key code back in place. It is very important to understand what happens next, as the failover scenario can result in very subtle errors. To illustrate the new chain of events, we will again show the WebSphere Application Server trace flow:

  • As in our previous scenario without the cache key, the attempt to connect to server1 via an MBean fails. But this time, the runtime sees the custom cache key in the LTPA token from the TAI. Since this indicates to WebSphere Application Server that a custom subject was created, WebSphere Application Server should not create the subject on its own; the TAI will have to be called. We can see this in the trace:

       [5/11/05 18:41:05:015 EDT] 00000035 distContextMa 3   Exception getting opaque 
    token from    originating server.
       com.ibm.websphere.security.auth.WSLoginFailedException: SSO token uniqueID not 
    null, but opaque token not found.  Need to re-challenge the user to login again.
    [5/11/05 18:41:05:075 EDT] 00000035 TrustAssociat 3   Check if target interceptor
     [1]: examples.was.login.ExampleTAI ...
       [5/11/05 18:41:05:075 EDT] 00000035 TAIWrapper    >  isTargetInterceptor() 
    Entry
       [5/11/05 18:41:05:075 EDT] 00000035 SystemOut     O   isTargetInterceptor 
    called
  • We now arrive at another very important point: When the TAI is invoked again, we do not have the original context that we had on the initial login, where the user had just filled out the login JSP and its contents were included on the request. Hence, the information (such as the administrative privileges checkbox) is not available. Given that this is essential to our decision tree in building the subject, we must detect this and then inform WebSphere Application Server that we cannot process this request.

  • This information causes WebSphere Application Server to continue with normal authentication (our sample application has a defined login page, so that is what it will be called). The code to handle this situation is below:

    if (fromLoginJSP == null || !fromLoginJSP.equals("Y")) {
    	// The TAI has been invoked, but the hidden flag that indicates
    	// that it is from the login JSP is not in place. This can happen
    	// in scenarios such as the user being failed over to another
    	// application server, and this new server being
    	// unable to retrieve the custom subject via the cache key.
    	System.out.println("Didn't come from login JSP. Default behavior 
    will occur.");
    	return false;
    } else {
    	System.out.println("TAI will handle request.");
    	return true;
    }
  • Notice that we used a hidden field in the login JSP to facilitate this; the TAI checks for the presence of this field to decide whether it is being called as a result of the login JSP being submitted. It would not have been good enough to simply check for the presence of the administrative privileges checkbox; due to the nature of the HTTP protocol, this variable is not included in the request parameters if the box is not checked. The resulting screen is shown in Figure 13, which displays because the application has defined a login page in web.xml. Our TAI had nothing to do with the display of this page.

Figure 13. Redirect back to the login JSP with error
Figure 13. Redirect back to the login JSP with error

In cases where the custom subject is not context-sensitive, the TAI can proceed to recreate the subject. If you are using a front-end proxy authenticator, such as IBM Tivoli Access Manager WebSEAL, this will normally be OK, since all necessary context will have been provided. If the subject is recreated, WebSphere Application Server would then create a new LTPA token with the correct server name and admin port number for the server that re-authenticated the user, in this case server2. You will need to be more cautious about this type of error trapping when using your own TAI if it relies on dynamic or environmental factors to modify the subject.

(If you are wondering why our TAI always creates a subject even when the subject just contains default group information, we do this to work around a problem with subject caching. See the cache issues section for more.)


JAAS usage

JAAS login configurations

JAAS login modules

As described in the authentication plug points section, custom JAAS login modules can be added to the WebSphere Application Server login configurations to modify the subject. Typical uses of such user-written login modules are to assert some user identity to WebSphere Application Server, or to perform custom identity mapping.

For a login module to assert user identity information to WebSphere Application Server, it must execute prior to the IBM ltpaLoginModule (which creates the user credentials) and place a hashtable of user information in one of two places in the subject: either in the sharedState or the public credentials areas, both of which are normally used portions of any JAAS login module sequence. This user identity assertion must be performed in the JAAS login() method.

Here is a small code fragment showing where to place this in the subject -- this being the shared subject that all JAAS login modules have access to:

subject.getPublicCredentials().add(hashtable);

The hashtable shown here is assumed to have been created with the exact same format as was shown earlier in the TAI example. The WebSphere Application Server ltpaLoginModule will see this hashtable when it executes its login() method, but rather than authenticating the user and querying the registry, it will directly create credentials using the information found in the hashtable instead. Note that there can be only one hashtable in the subject, otherwise this will become ambiguous. We therefore prefer to place the hashtable in the sharedState area using a well defined key, as follows:

sharedState.put(AttributeNameConstants.WSCREDENTIAL_PROPERTIES_KEY, hashtable);

If you are unfamiliar with how to obtain the sharedState object or the subject in a JAAS login module, refer to the Java documentation for JAAS. Both are provided as part of the initialize() method to the login module.

Callbacks available to login modules

As mentioned earlier, JAAS login modules can use callbacks to obtain information relevant to the authentication from the environment. WebSphere Application Server supports several callbacks, which are described in detail in the WebSphere Application Server Information Center.

This table summarizes the available callbacks, and details when a callback is available depending on the login configuration being executed.

Table 1. Available callbacks
CallbackWEB_INBOUNDRMI_INBOUNDRMI_OUTBOUNDDEFAULT
NameCallbackavailableavailablenot availableavailable
PasswordCallbackavailableavailablenot availableavailable
WSCredTokenCallbackImplavailableavailablenot availableavailable
WSTokenHolderCallbackavailableavailablenot availableavailable
WSServletRequestCallbackavailablenot availablenot availablenot available
WSServletResponseCallbackavailablenot availablenot availablenot available
WSAppContextCallbackavailablenot availablenot availablenot available
WSProtocolPolicyCallbacknot availablenot availableavailablenot available

Login types

It is important to understand that login modules are not only called at initial login time; they are called whenever WebSphere Application Server needs to refresh credentials on an application server. As a result, all callback information will not always be available to the login module. This is because some callbacks provide environmental information that is specific to the particular request invocation. For example, if a login module looks for a particular field in a request object - assuming that the user has just provided it - that same login module might fail in another scenario where the user has not just entered input. There are three distinct login scenarios, described here (and discussed further later):

  • Initial login - The true first login and authentication by a user. At this time, all callback information, including any user input, should be available.

  • Initial login with SSO token - This will normally never occur with custom login modules that have properly created a custom cache key. In a Web-based environment, this type of login can occur when the client hits a different server that cannot access the user's subject (which has been cached by the WebSphere Application Server security runtime). The default behavior at this time will be to re-authenticate, which means calling the TAI if one exists, or otherwise performing the normal WebSphere Application Server authentication process. This is the ordinary login process. However, there is an option available to enable the login to take place without the subject being available, which means that the JAAS login modules will be called. We will discuss this more later.

  • Propagation login - In this scenario, a new server has been accessed and the subject is available, but additional verification is required. More precisely, the tokens that represent the subject are available and the subject is to be recreated from the tokens (we will discuss tokens more shortly). In this case, a typical custom login module will generally do nothing. Only login modules that manipulate custom tokens are likely to require any action be performed. In recognition of that, WebSphere Application Server provides a simple method on the existing WSTokenHolderCallback for determining if this is a propagation login. Custom login modules that do not have any meaningful work to perform can easily check for this case. Here is a brief example:

    if (callback.requiredLogin()) {
    //initial login or initial login w/ SSO case
    } else {
    //propagation login. No work required
    return true.
    }

JAAS module vs. TAI

One obvious question might be when to use a TAI versus login modules for asserting identity information. In general, you want to use TAIs for Web requests if at all possible, because of their simplicity. The table below shows the differences between the two:

Table 2. JAAS module vs. TAI
FeatureLogin moduleTAI
IBM proprietaryNo, but requires WebSphere Application Server specific code anywayYes
Ease of Usehardereasier
Multi-phase authenticationNoYes
Suppress Web login challenge*NoYes
Can be used for Web callsYesYes
Can be used for RMI callsYesNo
(Re)called for propagation loginsYesNo

* Before the login modules are even invoked, WebSphere Application Server will have challenged the user for their current authentication information. Obviously, if you are trying to develop a Web-based SSO solution, a TAI is the better approach.

As a basic rule of thumb, it is more appropriate to use TAIs for Web authentication and login modules for other situations.

Proxy login modules

Before you can configure your own login modules, we should explain one potentially confusing item when configuring a custom JAAS login module. JAAS is part of the JRE and by default can only see the JVM lib and ext classpaths. To simplify classloading issues, and to keep your JAAS login modules out of the JVM classpath, IBM provides a proxy login module that uses thread-based classloaders, enabling you to place your own custom login modules in the usual places, such as WebSphere Application Server/lib/ext. Figure 14 shows the configuration of a login module where the proxy login module is specified by checking the box for this option.

Custom JAAS login module examples

Example: Identity assertion login module

Our second example shows how to assert portions of a user's identity to WebSphere Application Server and modify the user's group associations dynamically by using a JAAS login module. Since login modules are more likely to be used with RMI/IIOP, our example uses a simple Java client that contacts an EJB running in WebSphere Application Server. We will not show the EJB client or server code here, since these are irrelevant to the example. Just know that the EJB server code prints out the user subject information just like our earlier servlet example. The EJB implements a single remote method, reverseString(). (The complete client and EJB source code are included in the download file as two additional EAR files: ReverseClientEAR.ear and ReverseEJBEAR.ear.)

Our custom login module is named MyBeforeLTPALoginModule. It is in loginexamples.jar which should be placed in WAS-INSTALL/lib/ext. To assert the user information to WebSphere Application Server before it creates the subject on its own, we will insert our login module before the WebSphere Application Server modules on the RMI_INBOUND JAAS login module stack. Figure 14 shows how to configure the login module using the administrative console. Notice that the proxy checkbox discussed above has been selected.

Figure 14. RMI_INBOUND login module proxy being added
Figure 14. RMI_INBOUND login module proxy being added

Figure 15 shows the pane that is displayed after the module has been added. Notice that the default is to add it at the end of the stack, third in order as shown. We will need to use the highlighted Set Order button to fix this.

Figure 15. MyBeforeLTPALoginModule added to the WEB_INBOUND stack
Figure 15. MyBeforeLTPALoginModule added to the WEB_INBOUND stack

Figure 16 shows the pane that is presented when using the Set Order control to change the order of the login modules. In this figure, we have already selected the radio button for our login module and pressed the Move Up button twice to move it to be at the top of the stack.

Figure 16. The Set Order admin console pane
Figure 16. The Set Order admin console pane

Pressing OK in the Set Order pane presents Figure 17. It may be disconcerting at first to see the new login module still at the bottom of the order, but this is only due to the default alphabetical ordering of modules. Looking at the Module order column confirms that our module is indeed the first in sequence.

Figure 17. The new RMI_INBOUND login module order
Figure 17. The new RMI_INBOUND login module order

Now let's see this login module in action:

  • We start our EJB client using launchClient. The EJB client connects to WebSphere Application Server and looks up our EJB and then calls it. As you might expect, the standard WebSphere Application Server authentication process applies so we will be challenged to provide our user ID and password (not shown). Listing 7 shows the launchClient process. If you want to run this example yourself, you will need to install the provided ReverseEJBEAR.ear application, which contains the components that are used by launchClient.

    Listing 7
    >launchclient
    "c:\home\presentationsPapers\AdvancedAuthPaper\ReverseClientEAR.ear"
    -CCBootstrapPort=2810 hello
    IBM WebSphere Application Server, Release 6.
    J2EE Application Client Tool
    Copyright IBM Corp., 1997-2004
    WSCL0012I: Processing command line arguments.
    WSCL0013I: Initializing the J2EE Application Client Environment.
    [6/20/05 9:47:04:923 EDT] 0000000a  W UOW=null source=com.ibm.ws.util.ImplFactory 
    org=IBM prod=WebSphere component=Application Server thread=[P=223911:O=0:CT]
              WSVR0072W: Ignoring undeclared override of interface, 
    com.ibm.websphere.cluster.topography.DescriptionManager, with implementation, 
    com.ibm.ws.cluster.topography.ClientDescriptionManager
    WSCL0035I: Initialization of the J2EE Application Client Environment has completed.
    WSCL0014I: Invoking the Application Client class Main
    String provided: hello
    String in reverse: olleh
  • After the authentication challenge takes place, the RMI_INBOUND login module configuration is called. Our custom login module gets control first. In the initialize() method, the references to the subject and callbackhandler are stored.

    Listing 8
    public void initialize( Subject subject, CallbackHandler callbackHandler, 
    Map arg2, Map arg3 ) {
    
    System.out.println( "MyBeforeLTPALoginModule initialize()" );
    this.subject = subject;
    this.callbackHandler = callbackHandler;
    }
  • Next, the login() method is called by the WebSphere Application Server security runtime. The code shown below is executed in the login() method. Much of this should look familiar, as it is similar to what we did in the TAI example. One area of code that is new, and of particular interest, is the callbackHandler section (discussed earlier). In this particular context, our login module calls out to the JAAS callback handlers provided by WebSphere Application Server to retrieve the username and password that were entered on the basic authentication screen. Also, notice that we used the code described in the login types section to check for the propagation login scenario using the WSTokenHolderCallback. The string arguments to the username and password callbacks may seem superfluous, but providing empty strings results in an IllegalArgumentException.

    Listing 9
    public boolean login() throws LoginException  {
    	System.out.println( "MyBeforeLTPALoginModule login()" );
    
    	Callback callbacks[] = new Callback[ 3 ];
    	try {
    		callbacks[ 0 ] = new WSTokenHolderCallback( "" );
    		callbacks[ 1 ] = new NameCallback( "User:" );
    		callbacks[ 2 ] = new PasswordCallback( "Password:", false );
    		callbackHandler.handle( callbacks );
    	} catch ( Exception e ) {
    		System.out.println( "Login Module failed: " + e );
    	e.printStackTrace( System.out );
    		throw new LoginException( e.getMessage() );
    	}
     
    	boolean requiresLogin = ( (WSTokenHolderCallback)callbacks[ 0 ] ).
    		getRequiresLogin();
    	if ( requiresLogin ) {
    		System.out.println( "MyBeforeLTPALoginModule: Need to do stuff for an 
    			initial login" );
    		String username = ((NameCallback)callbacks[ 1 ]).getName();
    		String password = new String( ((PasswordCallback)callbacks[ 2 ]).
    			getPassword() );
    		 ((PasswordCallback)callbacks[ 2 ]).clearPassword();
    		Hashtable hashtable = new Hashtable();
    		String uniqueid = null;
    		try {
    			InitialContext ctx = new InitialContext();
    			UserRegistry reg = (UserRegistry)ctx.lookup( "UserRegistry" );
    			uniqueid = reg.getUniqueUserId( username );
    			reg.checkPassword( username, password );
    		} catch ( Exception e1 ) {
    System.out.println( "Login Module failed: " + e1 );
    			e1.printStackTrace( System.out );
    			throw new LoginException( e1.getMessage() );
    		}
    		System.out.println( "uniqueid = " + uniqueid );
    		hashtable.put( AttributeNameConstants.WSCREDENTIAL_UNIQUEID, 
    			uniqueid );
    		hashtable.put( AttributeNameConstants.WSCREDENTIAL_SECURITYNAME, 
    			username );
             
    // Assert the user as belonging to only this group. This is done only 
    // as an example of how to manipulate the user's groups dynamically. 
    // We could also have looked up the user's groups in the registry with
    // reg.getUniqueGroupIds() and added this one, or subtracted others 
    // from that list.
    ArrayList groups = new ArrayList();
    groups.add( 0, "nomemb" );
    hashtable.put( AttributeNameConstants.WSCREDENTIAL_GROUPS, groups );
    
    	// Set unique cache key to prevent cache problems (losing custom
    // info, etc) since the info is always the same for the user, I 
    // just prefix this with
    	// the login module name and userid.
    // But, if the info was unique to *this login* I'd need a more
    		// unique value...
    	System.out.println( "Using new cache key" );
    	hashtable.put( AttributeNameConstants.WSCREDENTIAL_CACHE_KEY,
     uniqueid + "ExampleBeforeLTPALoginModule" );
    	subject.getPublicCredentials().add( hashtable );
    	return true;
    	} else{
    		System.out.println( "MyBeforeLTPALoginModule: This is a repeat 
    			login, nothing to do." );
    		return true; 
    	}
    }
  • The only other significant code in this module is to return true from the commit() method. Listing 10 shows the edited output from the server side EJB. The EJB itself does nothing of interest in our example other than print out information about the current user. Notice that the user has been placed in to the group we asserted, rather than whatever groups might have been found in the WebSphere Application Server registry.

    Listing 10
    [6/20/05 10:14:19:503 EDT] 00000057 SystemOut     O MyBeforeLTPALoginModule 
    initialize()
    [6/20/05 10:14:19:503 EDT] 00000057 SystemOut     O MyBeforeLTPALoginModule login()
    [6/20/05 10:14:19:503 EDT] 00000057 SystemOut     O MyBeforeLTPALoginModule: Need to do 
    stuff for an initial login
    [6/20/05 10:14:19:503 EDT] 00000057 SystemOut     O uniqueid = user:customRealm/3
    [6/20/05 10:14:19:503 EDT] 00000057 SystemOut     O Using new cache key
    [6/20/05 10:14:19:533 EDT] 00000057 SystemOut     O MYAfterwsMapLoginModule being 
    loaded
    [6/20/05 10:14:19:533 EDT] 00000057 SystemOut     O MYAfterwsMapLoginModule 
    initialize()
    [6/20/05 10:14:19:533 EDT] 00000057 SystemOut     O MyAfterWsMapLoginModule login()
    [6/20/05 10:14:19:533 EDT] 00000057 SystemOut     O MyBeforeLTPALoginModule commit()
     [6/20/05 10:14:20:755 EDT] 00000056 SystemOut     O In reverseString
    [6/20/05 10:14:20:765 EDT] 00000056 SystemOut     O The WebSphere Application Server 
    Subject layer thinks you are keys
    [6/20/05 10:14:20:765 EDT] 00000056 SystemOut     O Looking into your Subject I see 
    these groups: 
    [6/20/05 10:14:20:765 EDT] 00000056 SystemOut     O Group ID: group:customRealm/nomemb
    [6/20/05 10:14:20:765 EDT] 00000056 SystemOut     O looking into Subject for custom 
    stuff

A more sophisticated login module could have asserted a different, arbitrary user ID and group information. The key is that the login module, because it is asserting the user information to WebSphere Application Server, takes on the responsibility for authentication. In our simple example, we used the WebSphere Application Server registry, but you could easily develop your own much more customized authentication approach.

Example: Subject modification login module

Our next example shows how a login module can be used to alter the subject after it has been created by WebSphere Application Server. To accomplish this, we will place our login module after the wsMapDefaultInboundLoginModule per our earlier discussion. Figure 18 shows the login module being added to the RMI_INBOUND configuration.

Figure 18. Custom login module configuration
Figure 18. Custom login module configuration

Figure 19 shows our custom login module in place with the two standard WebSphere Application Server system modules for RMI_INBOUND. Our login module is placed in the appropriate place to modify the subject after WebSphere Application Server has created it, which is after the wsMapDefaultInboundLoginModule. There is no need to change the order as we did in the last example, since the default places it where it needs to be, at the end of the stack.

Figure 19. Custom login module placement
Figure 19. Custom login module placement

We will use the same session EJB as in the last example, which will result in the same basic authentication process as before:

  • Login again as the same user. When the user is authenticated, the login modules are executed on the RMI_INBOUND configuration. The two standard WebSphere Application Server modules (seen in Figure 19) are executed, and then control reaches our module. The initialize() method shown below, in which we store off the reference to the subject for later use, is executed.

    Listing 11
    public void initialize( Subject subject, CallbackHandler arg1, 
    Map sharedState, Map arg3 ) {
    
    System.out.println( "MYAfterWsMapLoginModule initialize()" );
    	this.subject = subject;
    }

    Next, the login() method is called:

    Listing 12
    public boolean login() throws LoginException{
    System.out.println( "MyAfterWsMapLoginModule login()" );
    	return true;
    }
  • This would be the point where, in some cases, we might perform authentication of the user, such as in our earlier example, where we assert the user's identity to WebSphere Application Server. In this case, since we are letting WebSphere Application Server create the Subject, authentication is not necessary and we can simply return true. The subject is not fully formed at this point, so we will not attempt to alter it here.

  • The next method to gain control in our login module is commit() and, in our case, this is where the real action happens:

    Listing 13
    public boolean commit() throws LoginException {
    	String id = null;
    	System.out.println( "MyAfterWsMapLoginModule commit() " );
    	Set stuffset = subject.getPublicCredentials( CustomJAASStuff.class );
    	if ( stuffset != null && stuffset.isEmpty() ) {
    		System.out.println( "MyAfterWsMapLoginModule never been called before." );
    		CustomJAASStuff stuff = new CustomJAASStuff();
    		Set principals = subject.getPrincipals(); 
    		if ( ( principals != null ) && ( !principals.isEmpty() ) ) {
    			Iterator iter = principals.iterator();
    Principal p = (Principal)iter.next();
    			id = p.getName();
    		}
    		StringBuffer id2 = null;
    		id2 = new StringBuffer( id );
    		stuff.setWord1( "Caller principal in caps = " + id.toUpperCase() ); 
    		stuff.setWord2( "Caller principal in reverse = " + 
    			id2.reverse().toString() ); 
    		System.out.println( "MyAfterWsMapLoginModule: adding to subject" );
    		subject.getPublicCredentials().add( stuff );
    } else {
    System.out.println( "Found existing CustomJAASStuff. Must be a reinvocation." ); 
    		return true;
    	}
    }
  • For this example, we have created a plain old Java object (POJO) class that contains a few string objects (word1, word2) and a date object. First, we ensure the class does not already exist, and then we instantiate one for our use. The code retrieves the principal from the subject, and the user ID is retrieved from that. The two String objects in CustomJAASStuff are populated with the user ID, converted to all capitals and reversed. The custom object is then added to the public credentials of the subject, and our commit() method returns true, which commits our changes to the subject.

  • The following code has been added to the EJB to check for our modifications when the subject is passed to it:

    Listing 14
    System.out.println("looking into Subject for custom stuff");
    Set set = WSSubject.getCallerSubject().getPublicCredentials(
    CustomJAASStuff.class);
    if ((set != null) && (!set.isEmpty())) {
    System.out.println("your subject appears to have a CustomJAASStuff in it");
    	iter = set.iterator();
    	int i = 1;
    while (iter.hasNext()) {
    		System.out.print("#" + i);
    		CustomJAASStuff stuff = (CustomJAASStuff) iter.next();
    		System.out.print(": And in it I find word1 = "
    			+ stuff.getWord1());
    		System.out.println(". And the date is "
    			+ stuff.getDate());
    i++;
    	}
  • The results are shown in Listing 15.

    Listing 15
    [6/20/05 9:47:17:301 EDT] 00000057 SystemOut     O MYAfterwsMapLoginModule being loaded
    [6/20/05 9:47:17:301 EDT] 00000057 SystemOut     O MYAfterwsMapLoginModule initialize()
    [6/20/05 9:47:17:301 EDT] 00000057 SystemOut     O MyAfterWsMapLoginModule login()
    [6/20/05 9:47:17:301 EDT] 00000057 SystemOut     O MyAfterWsMapLoginModule commit() 
    [6/20/05 9:47:17:311 EDT] 00000057 SystemOut     O MyAfterWsMapLoginModule never been 
    called before.
    [6/20/05 9:47:17:311 EDT] 00000057 SystemOut     O MyAfterWsMapLoginModule: adding to 
    subject
     [6/20/05 9:47:19:013 EDT] 00000056 SystemOut     O In reverseString
    [6/20/05 9:47:19:033 EDT] 00000056 SystemOut     O The WebSphere Application Server 
    Subject layer thinks you are keys
    [6/20/05 9:47:19:033 EDT] 00000056 SystemOut     O Looking into your Subject I see 
    these groups: 
    [6/20/05 9:47:19:033 EDT] 00000056 SystemOut     O Group ID: group:customRealm/2
    [6/20/05 9:47:19:033 EDT] 00000056 SystemOut     O looking into Subject for custom 
    stuff
    [6/20/05 9:47:19:033 EDT] 00000056 SystemOut     O your subject appears to have a 
    CustomJAASStuff in it
    [6/20/05 9:47:19:033 EDT] 00000056 SystemOut     O #1: And in it I find word1 = Caller 
    principal in caps = CUSTOMREALM/KEYS. And the date is Mon Jun 20 09:47:17 EDT 2005
  • Notice that our login module is called in the "initial login" state. After our login module completes, the reverseString EJB method executes and simply prints out the subject, which, you may notice, contains the custom information we placed in it (CustomJAASStuff). Also, the user group here is different from the previous example even though we did authenticate as the same user. That is because rather than assert user or group information in this login module, we let WebSphere Application Server get it from the user registry.


Propagation

Overview

Earlier, we discussed requirements for integrating custom logic with the authentication model supported by WebSphere Application Server, making use of both the TAI interface and the ability to add custom JAAS login modules to the supported login configurations. What this custom logic does is add information to the JAAS subject that affects the security attributes of the application; that is, the custom information that was added to the subject may be used within the application to make additional, finer grained, authorization decisions. This can include the use of calculated or dynamic group information that is not stored in any registry.

It is possible for custom JAAS login modules to add information to the subject during a system login. This might include generic Java objects which may or may not be serializable. However, it is important to remember that you are probably not running on a single, standalone server, so there are implications as to exactly what you add to the subject for it work as expected in a distributed environment.

The problem with attempting to recreate custom data is that it is not always possible to do so. In some cases, the custom data generated at the first server may have been dynamically derived. For example, one can derive a location identifier based on the originating browser's IP address, derive a specialized role from a form login attribute, or gather authorization attributes specific to the time-of-day that the login first occurred. These are examples of dynamic authorization attributes that could be lost as soon as a user moves to a second server.

To be useful in a distributed, clustered environment, it must be possible to propagate this custom subject. There are two distinct types of propagation that we will address:

  • Horizontal propagation involves making the subject available to all application servers that are accessed by Web clients.
  • Downstream propagation is the ability to pass custom credentials via the RMI/IIOP layer.

Tokens

For propagation to occur, subject information needs to be transmitted over the network. WebSphere Application Server uses Java serialization for custom objects that have been added to the subject; it is therefore essential to use good serialization practices, as defined by Sun™, to support version-to-version compatibility. WebSphere Application Server itself does not depend on Java serialization for transmitting its own information. Instead, WebSphere Application Server relies on a token framework, where tokens represent various aspects of a user's identity or the subject. The token types used by WebSphere Application Server are:

  • Authentication token - Represents a user identity (not groups, just base identity) and flows downstream over RMI/IIOP connections; equivalent to the older (pre-WebSphere Application Server V5.1.1) version of the LTPA token.

  • Single sign-on (SSO) token - Used for horizontal propagation of user identity, this token is converted to a cookie and sent back to the browser, and is analogous to the older version of the LTPA cookie. The SSO token is essentially another version of an Authentication token that is suitable for use with a Web browser.

  • Authorization token - A new token type that contains most of the user information from the subject, including all group information.

These tokens represent aspects of the subject. A fourth token, the propagation token, is not user specific, but it represents the thread context for downstream propagation. The propagation token will not be discussed here.

Although not covered in this article, it is possible to develop your own tokens based upon one of these four types, enabling you to control how information is actually propagated from server to server. It is even possible to customize the network representation of the pre-defined WebSphere Application Server tokens. Refer to the WebSphere Application Server Information Center for details.

Horizontal propagation

Horizontal propagation is about the ability of credentials (that is, a subject) created on one server to be made available when the same client accesses another server, without passing through an intermediary server (for example, Web authentication).

As we have seen already, a subject is created when a user signs on to WebSphere Application Server. For Web clients, an SSO token is also created and sent back to the browser. This token does not contain the user identity in full; it contains enough information to uniquely identify - and thus retrieve or recreate - a user's subject. The cache key we mentioned earlier is part of the SSO token. When the subject is created, it is placed in the application server's security cache. It can also, for a clustered environment, be configured such that the tokens representing the subject are stored in DynaCache and replicated. In this scenario, if the user accesses a different application server in the cluster, the set of tokens that make up the subject can be retrieved using the SSO token as a key, and then the custom subject can be recreated.

The SSO token contains a unique ID and timestamp that represents the user, optional custom key information, and JMX admin endpoint information for the application server that created (and cached) the subject. When the user accesses an application server with an SSO token, the following steps are taken to retrieve the subject:

  1. The local security cache is searched for an existing, instantiated subject. If the subject is found in the cache, it is associated with the current thread and then used for security purposes.

  2. If the subject is not found in the local cache, DynaCache is searched for the token set that can be used to recreate the Subject. If the tokens are retrieved from DynaCache, a propagation login is performed.

  3. If the DynaCache lookup is not successful, then the JMX endpoint of the originating server is accessed via JMX and the token set is requested. If the tokens are retrieved via JMX, a propagation login is performed.

Figure 20 illustrates this process.

Figure 20. Authentication state diagram
Figure 20. Authentication state diagram

As you can see from the diagram, there are various paths that can be taken depending on the specific situation. As mentioned earlier, there are three distinct login scenarios: initial login, initial login with SSO token, and propagation login. Some of the subtleties associated with the login and propagation processing will be discussed later.

DynaCache usage

WebSphere Application Server creates a private security cache in DynaCache. Tokens representing the subject are placed in the cache by the application server and replicated to the replication domain. This is typically a single WebSphere Application Server cluster within a single cell, so when a Web client accesses a different cluster or cell, the subject will not be available via DynaCache and the system will fallback to JMX access (described next). When tokens are obtained from DynaCache and used to recreate the subject, this results in a propagation login, which works rather differently from an initial login, as shown in Figure 21.

JMX usage

When the subject information is not available from either the local application server security cache or from DynaCache, the runtime will attempt to retrieve the tokens by making a secure JMX admin call to the server that performed the original initial login. Using tokens retrieved by JMX also results in a propagation login. It is possible that the JMX call will fail, either because the originating server is not currently available, or because the credentials are no longer available in the security cache. In this case, the currently accessed server will perform an initial login with the SSO token. The specific behavior in this situation will be described later.

Be aware that if the JMX call crosses cell boundaries, the two cells must share a common security infrastructure -- the same registry, the same LTPA encryption keys, compatible SSL keys, and so on. It is also necessary that the calling application server's identity (the cell security server ID) has administrative authority on the server it is contacting. Only a process with administrative authority can obtain security tokens from another process.

Propagation login vs. initial login

Figure 21 shows the different flow of control between an initial login and a propagation login. Basically, the difference is that a propagation login merely instantiates a Subject using existing information (the tokens), and does not actually authenticate using a registry. On the other hand, an initial login is expected to create the user subject from the available information (perhaps as little as the SSO token).

Figure 21. Login types
Figure 21. Login types

Downstream propagation

Downstream propagation is very different from horizontal propagation. In downstream propagation, an application server that has access to the complete user's subject is calling another application server. There is no need here for the sharing features of an SSO token or complex horizontal subject propagation.

  • When an application server calls a second server, some information needs to be sent along with the request to continue identifying the user for access to the next resource. The information sent depends upon the J2EE RunAs mode (that is, client, server, or specified). The most common RunAs mode is client, which preserves the originating client identity. When RunAs client is specified in the application's deployment descriptor, the authenticated user subject is set as the invocation subject on the thread ready to be used for any outbound request.

  • As with Web propagation, the subject is converted to tokens and these tokens are propagated to the downstream server.

  • Upon receipt, the tokens are converted back into a subject via a propagation login. This handshaking occurs as part of the CSIv2 context negotiation. The resulting subject is associated with the CSIv2 session.

  • Once a CSIv2 session is established between two parties (including an EJB client), the information in it will remain cached for an extended period. Generally speaking, the session will remain as long as the credentials are still valid. Thus, for example, if an EJB client connects to an application server and remains connected while performing various EJB operations, a custom login module will be called when the client connects and then not again until the client's authentication token expires (two hours by default).

Downstream propagation uses the RMI_INBOUND and RMI_OUTBOUND login configurations. RMI_OUTBOUND is used on the sending server and RMI_INBOUND on the receiving server, as shown earlier. You can customize what is sent by the upstream server by adding your own login modules to the RMI_OUTBOUND login configuration. For example, you might want to perform some kind of identity mapping at this point.

Client differences

A standalone J2EE client can perform a JAAS login and then make method calls on EJBs in an application server. When this occurs, a subject is created on the server. This can be a custom subject created using a custom JAAS login module. However, there are some issues.

First, since there is no SSO token on the client in this scenario, and the custom subject is on the server, not the client, there is no way to perform a propagation login if a client accesses another server (either on failover, or just using another server), and a full initial login will take place at the time the new CSIv2 session is created.

Second, since a full initial login occurs on every access to a new server, there can be problems with repeating the authentication. For example, it is possible that the authentication data is no longer valid, perhaps because the user authentication password is time sensitive.

If a custom Subject is created at the client, it will be propagated to each server instance as part of the initial login, but if it was created on the server by login modules, it must be recreated at the new initial login. Unfortunately, it is not appropriate to store security information at the client since clients are subject to compromise and generally outside the trust domain. As a result, if you are using Java clients with WebSphere Application Server, you need to think carefully about your design if custom subjects are to be used, because it will be very difficult to share them.

Go back and try the Java client example again. Change the client to connect to two application servers. Notice that the custom login module is called the first time each application server is contacted and the custom subject is recreated.

Propagation: The big picture

Figure 22 shows various aspects of propagation. You will see that attributes are propagated horizontally (for Web SSO) using DynaCache, while attributes are propagated downstream (for RMI requests) using RMI. This is because WebSphere Application Server can propagate attributes directly as part of the CSIv2 protocol for RMI/IIOP requests, only the SSO token is provided to other servers by the Web client for Web requests. Notice also that there is a fallback mechanism in the Web layer. In the event that a Web SSO request arrives at an application server that is not part of the DynaCache replication domain (perhaps it is in another cluster or even another cell), a JMX call is made to the originating application server to obtain the custom subject information. Fallback is not needed for RMI propagation since the calling server simply sends the tokens on the request.

Figure 22. Propagation
Figure 22. Propagation

Issues with horizontal propagation

Propagation is an extremely complex issue, with many subtle complexities you need to be aware of. As discussed earlier, there are several places in which you as a developer have the ability to customize how WebSphere Application Server authentication works. You can add a custom TAI or JAAS login module, you can add custom attributes to the subject, or even alter the way in which WebSphere Application Server creates credentials, thus bypassing the normal registry lookups. When you do this, you need to be very conscious of the issues that can occur, particularly with what happens in a multi-server environment, and how propagation and failover work. In this section, we will try to address some of these issues and point out some good practices.

When you perform an initial login, you can customize the subject in either a TAI or a login module. The subject will be created in the application server that you initially access and stored locally in the security cache. It will also be added in token form to a private cache managed by DynaCache, and thus potentially made available to all servers in the same replication domain as the original server. If the subject is a standard WebSphere Application Server subject with no modifications, then the subject can be stored using the default cache key, which is guaranteed to be unique for a given user. However, if you have modified the subject, then you will need to augment the cache key with data that is sufficiently and appropriately unique for the situation. Otherwise, if WebSphere Application Server can't find your cached subject for whatever reason, it will simply recreate a default subject when you hit a different application server.

As far as "appropriate uniqueness" is concerned, this is application specific. If the custom subject is always recreated in the same way, then a simple string including the user's unique ID and some additional string constant is sufficient. However, if two logins for the same user create different subjects (because the content of the Subject varies by, for example, the time of day at login, or location of login device), then the cache key would need to contain sufficient information to ensure different cache keys for different subjects for the same user. For example, the key may contain a hash based on the time, or on the IP address of the login device. The unique cache key information is placed by WebSphere Application Server within the SSO token. Remember that the SSO token is the one and only piece of information that is guaranteed to be shared between application servers when performing Web-based SSO.

When you use a Web browser to access a server other than the one to which you originally authenticated, WebSphere Application Server will attempt to locate the subject as previously described, looking first in the local cache, then in DynaCache, and finally attempting to retrieve the required tokens via a JMX call to the originating server. If the tokens required to recreate the Subject cannot be located by these methods, then things get tricky:

  • If there is no custom cache key, WebSphere Application Server will simply perform an initial login using the SSO token as the user's authentication data. The login modules are responsible for recreating the user's subject given only that SSO token. This is exactly the same as the WebSphere Application Server behavior when propagation is not enabled.

  • If there is a custom cache key, then by default, WebSphere Application Server will attempt to re-authenticate the user. That is, the SSO token will be ignored and a normal "authenticate from scratch" will be performed. That means that TAIs will be invoked if available, the user will be challenged to authenticate if needed, and then an initial login will be performed. This may be frustrating to your users.

  • If there is a custom cache key, but the default behavior has been overridden by setting com.ibm.ws.security.webChallengeIfCustomSubjectNotFound to false for the security subsystem (set via the Global Security Additional properties panel), WebSphere Application Server will attempt to carry on without re-authenticating the user. Instead, an initial login will be performed using only the SSO token. Your custom login modules, if any, will be invoked.

Important version note

The behavior described above with respect to the handling of a failed propagation login with a custom cache was altered with APAR PK00852 which is part of WebSphere Application Server V5.1.1.4 and WebSphere Application Server V6.0.1. You must use these versions of WebSphere Application Server for propagation to behave properly in the error case. With earlier versions, the custom cache key will be ignored and the user's subject will silently change to the default value.

If you override the default behavior by setting the com.ibm.ws.security.webChallengeIfCustomSubjectNotFound property, when the subject is lost and an initial login is performed, all that is available to the login modules at this point is the SSO token (and the cache key which is contained in the SSO token). If this provides sufficient information for the login module to correctly create the subject, then it can continue; otherwise it needs to terminate with an error, which will force the authentication to fail. Note that at this point you are stuck: you cannot login successfully, but WebSphere Application Server will not attempt to re-authenticate. The only way to force re-authentication is to destroy the SSO token by shutting down the browser. You should not allow this situation to occur. If you cannot guarantee that your login module can successfully work with only an SSO token, take the default approach of letting WebSphere Application Server repeat the authentication process. This is why the default behavior is to re-authenticate. Only change this if you are sure your login modules can recover.

Notice how the login modules have more responsibility and opportunity for handling complex login scenarios than does a TAI. This is not accidental: login modules provide added flexibility, but at a price. When you write login modules, you are actively integrating with the WebSphere Application Server security runtime, and need to fully comprehend the complexity involved in doing so. The TAI has been kept intentionally simple, and is generally a preferred customer interface in cases where it can be used.

Cache issues

  • Clearing caches

    The lifetime for cached tokens placed in DynaCache is the same as that of the SSO token. Thus, the cached subject data will expire out of DynaCache when the corresponding SSO token expires.

    The JMX SecurityAdmin clearAuthCache call (see the WebSphere Application Server Information Center for details) that invalidates the security cache entry for a user also invalidates the user's subjects that are cached in DynaCache in addition to the authentication cache. However, the JMX clearAuthCache call does not invalidate the CSIv2 session cache. Therefore, using clearAuthCache will not force the user's subject to be re-computed when the client is using IIOP, unlike with Web clients. Of course, logging in again will result in a new subject being created since the old one is gone.

  • Authentication cache implications

    Be aware that WebSphere Application Server caches subjects in an authentication cache, which is accessible via many different lookup keys. Some example lookup keys include user ID, user ID and password, and LTPA token. When first authenticating a user, WebSphere Application Server will usually first attempt to find a cached Subject for the user (refer to the earlier state diagram), rather than creating a new subject. This improves performance but may yield unexpected results when using custom subjects.

    One key example of this behavior is with EJB client access: If the same user authenticates multiple times with the same user ID and password, the same cached subject will be used, even if the subject is customized on the server side. After the subject is created the first time, your login modules will not be called until the authentication cache expires because the only key WebSphere Application Server has for looking up the potentially cached subject is the user ID and password. You can prevent this behavior by customizing the subject on the client side, just by placing any custom value in it. WebSphere Application Server will then bypass the authentication cache and use the login modules to create the subject.

    Go back and try the Java client again. This time, connect repeatedly to the same application server as the same user. Notice that your custom login module is only called the first time. It won't be called again until the authentication cache expires (10 minutes by default).

    A second example of this behavior was described earlier in the TAI section. If a TAI returns just a user ID in the TAIResult object, WebSphere Application Server will look for a subject matching that user ID. This can result in WebSphere Application Server using a previously created and cached custom subject, rather than a default subject. This is why our TAI always creates a subject. In this case, we would prefer that WebSphere Application Server not cache the custom subject based on the user ID (it should use the custom cache key). This behavior means that if any TAI ever creates a custom subject, then every TAI (and login module) must consistently use custom cache keys. This is WebSphere Application Server internal defect #293814 (a fix is not currently available for any release). If this defect impacts you directly, consider contacting IBM Support and requesting a fix.

Enabling propagation

In WebSphere Application Server V6, propagation is enabled by default, so no further action is necessary. You can of course disable propagation if you like. In WebSphere Application Server V5.1.1, propagation is disabled by default. Propagation settings are controlled in two places:

  • The LTPA SSO configuration panel enables you to configure Web inbound security attribute propagation.
  • The CSIv2 Inbound and Outbound Authentication panels let you configure downstream security attribute propagation.

Conclusion

This article described the advanced authentication features available in WebSphere Application Server to support a more flexible authentication model, including the use of the new, enhanced TAI interface, as well as the custom JAAS login modules. Also discussed were some of the dangers that can trap the unwary developer when dealing with login propagation in a clustered environment.


Download

DescriptionNameSize
Code sampleWASAdvancedAuthentication.zip  ( HTTP | FTP )107 KB

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere, Tivoli
ArticleID=92125
ArticleTitle=IBM WebSphere Developer Technical Journal: Advanced authentication in WebSphere Application Server
publish-date=08172005