Achieve dynamic authentication in a Web services client using a custom JAAS callback handler

It is often the case that a statically defined username and password in the Web services deployment descriptor is not appropriate. With the Java™ Authentication and Authorization Service (JAAS) callback handler described in this article, you have the option of using a properties file (or some other source) for dynamically setting username and password at run time for UsernameToken (UNT) authentication in a Web services client. This article describes a sample application that uses such a custom callback handler, enabling you to send a different username and password for each client application user. This content is part of the IBM WebSphere Developer Technical Journal.

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.



Peter Van Sickel (pvs@us.ibm.com), Consulting I/T Specialist, IBM

<b>Peter Van Sickel</b> is a Consulting I/T Specialist with IBM Software Services for WebSphere. Mr. Van Sickel has over 15 years of experience with distributed systems software development. He got his start in distributed system software with DCE and later the Encina OLTP monitor from Transarc Corporation, which was acquired by IBM. For the past 10 years he has focused on Java EE and WebSphere Application Server based systems including WebSphere Process Server. Mr. Van Sickel holds a Masters degree in Industrial Administration from Carnegie Mellon University, a Masters degree in Computer Engineering from Stanford University, and a B.S. in Electrical Engineering from Pennsylvania State University. Mr. Van Sickel is one of the authors of <a href="http://www.amazon.com/WebSphere-Application-Server-Step-Step/dp/1583470611">WebSphere Application Server Step by Step</a>.



18 July 2007

Also available in Chinese

Introduction

Using UsernameToken in combination with SSL is very common for authentication of a Web services client to a service provider. The default way to specify the username and password to be used in the service request is in the client side deployment descriptor as part of the configuration of UsernameToken security. The NonPromptCallbackHandler, provided as part of the IBM® WebSphere® Application Server runtime, will use the username and password in the client deployment descriptor to create the UsernameToken in the Web service request header.

However, there are many situations where you need something more dynamic than a username and password specified in the deployment descriptor. This article describes a custom JAAS callback handler that accommodates three options as sources of the username and password:

  • thread local storage
  • a properties file
  • from the client deployment descriptor, the same as the behavior of the NonPromptCallbackHandler.

The custom JAAS callback handler described here is called the ClientIdCallbackHandler; it is relatively short and this article explains how it works. The complete source code for a sample application demonstrating the use of the callback handler is included with this article. You will see how to configure the callback handler for the IBM WebSphere Application Server V6.0 runtime. IBM Rational® Application Developer 6.0 is also used here to demonstrate the configuration of the Web service deployment descriptors.

This article, which builds on an earlier developerWorks article that describes using UsernameToken and SSL for Web services security, assumes general familiarity with Java programming and Web services development.


Overview of the custom JAAS callback handler

When it is invoked on each request, the ClientIdCallbackHandler enables you to obtain username and password from a variety of sources. They are (in order of precedence):

  1. Username and password available in thread local storage.

    This is the highest precedence username and password. The values in thread local storage are set with the static method setThreadIdentity(String, char[]). After each use, the thread local storage values of username and password are reset to null. If you want to use a different username and password for each request, you need to place a call to setThreadIdentity() before each invocation of a given Web service operation.

  2. Username and password read from a properties file and set when the ClientIdCallbackHandler is instantiated.

    This is a use case for many applications. The username and password that are read from a properties file when the ClientIdCallbackHandler is instantiated are stored in instance variables named _appUsername and _appPassword, respectively. These instance variables are not reset and, if they are not null, are used to provide the username and password on every request. (This username and password is overridden by the thread local username and password if they are set for a given invocation.)

  3. Username and password provided in the module deployment descriptor as part of the configuration of the UsernameToken authentication.

    This is the lowest precedence username and password. The WebSphere Application Server runtime passes in a username and password that it pulls from the deployment descriptor when the JAAS callback handler is instantiated. The username and password that come from the deployment descriptor via the runtime are stored in _wasUsername and _wasPassword, respectively. These instance variables are only used if the other two sources of username and password are null, and are not reset after each use, so they can potentially be used on every request. (The most likely scenario for using the deployment descriptor username and password is during initial development testing.)

These high level steps describe the operation of ClientIdCallbackHandler:

  1. The WebSphere Application Server runtime invokes the ClientIdCallbackHandler constructor passing in a username and password and some properties. The constructor sets _wasUsername and _wasPassword and _properties from the input arguments. The constructor also invokes a method to load some configuration properties. If configuration properties are found, then an initUserIdAndPassword method is invoked to get a username and password from those configuration properties (Step 2).

  2. The initUserIdAndPassword method reads the Username and Password property and sets _appUsername and _appProperty instance variables for the ClientIdCallbackHandler. Notice that a base64 encoding of both the username and the password is used in the configuration properties file to avoid casual exposure of this sensitive information. Now the handler instance is ready to be invoked by WebSphere Application Server when the JAAS callback handler sequence is triggered by a service request in the client (Step 4).

  3. If the client needs to set a username and password for a given service request, then a call to setThreadIdentity(String, char[]) is placed in the code immediately before the actual service request invocation to set thread local storage for the username and password.

  4. The handle(Callback[]) method is invoked each time a service request occurs. The handle method is expecting these three types of callbacks: NameCallback, PasswordCallback, and PropertyCallback.

    1. For the NameCallback, the handle method uses the NameCallback setName method to set the username:

      1. First the handler checks the thread local storage username and uses it if it is not null.
      2. After using thread local storage, the handler sets the thread local username to null. It is clearly important to avoid inadvertent use of a given username and password that has been set on a given thread, so it is required that a thread specific username and password be set explicitly before each service request.
      3. If the thread local username is null, then the _appUsername value is checked and it is used if it is not null. If the _appUsername is null, then the _wasUsername is used.
    2. For the PasswordCallback, the handle method uses the PasswordCallback setPassword method to set the password. Similarly, the thread local password is checked and used if not null (and reset to null after use.) Otherwise, the _appPassword is used if it is not null. Lastly, the _wasPassword is used if the other two values are null.

    3. For the PropertyCallback, the handle method uses the PropertyCallback setProperties method to return the properties that were passed into it when the ClientIdCallbackHander was instantiated by the WebSphere Application Server runtime.

    If the handle method gets some other type of callback it throws an UnsupportedCallbackException.

ClientIdCallbackHandler up close

Specific sections of the ClientIdCallbackHandler source code are described here in detail. For descriptive purposes, some trace output statements have been replaced with brief comments.

These code sections are covered here:

  1. Class declaration and instance variables
  2. ClientIdCallbackHandler constructor
  3. loadConfigProperties method
  4. initUserIdAndPassword method
  5. setThreadIdentity method
  6. handle method

1. Class declaration and instance variables

Key things to note here are the thread local storage declarations and the instance variables used to hold the potential source of the username and password.

Listing 1. Class declaration and instance variables
public class ClientIdCallbackHandler implements CallbackHandler
{
  private static final String propertiesFileName = "login.properties";

  // thread specific username initalized to null;
  private static ThreadLocal username = new ThreadLocal()
  {
    protected synchronized Object initialValue()
    {
      return null;
    }
  };

  // thread specific password, also initialized to null;
  private static ThreadLocal password = new ThreadLocal()
  {
    protected synchronized Object initialValue()
    {
      return null;
    }
  };

  private Map _properties;
  private String _wasUsername; // value from WAS container
  private char[] _wasPassword; // value from WAS container

  private String _appUsername = null; // value from properties file
  private char[] _appPassword = null; // value from properties file

2. ClientIdCallbackHandler constructor

The constructor is invoked by WebSphere Application Server at the time of the first Web service request. Notice that the constructor is given static configuration information: the username, password, and properties.

Listing 2. ClientIdCallbackHandler constructor
  public ClientIdCallbackHandler(String username, char[] password,
      java.util.Map properties) throws IOException
  {
    super();

    Properties configProperties = null;

    this._wasUsername = username;
    this._wasPassword = password;
    this._properties = properties;

    configProperties = loadConfigProperties(propertiesFileName);
    if (configProperties != null)
      initUserIdAndPassword(configProperties);
  }

3. loadConfigProperties method

The loadConfigProperties method looks at a JVM system property named configuration.environment to get a prefix for the login.properties file name; for example, dev, test, qa, and prod are the prefixes used in the sample application. (The practice used in this particular example of reading properties files from the enterprise archive, while common, is not necessarily recommended. A more flexible approach is to use a URL resource to access a property file that can be placed anywhere in the file system.)

Listing 3. loadConfigProperties method
private Properties loadConfigProperties(String propertiesFileRootName)
{

  Properties configProperties = null;

  // Check the JVM property for the environment
  String myEnv = System.getProperty("deployment.environment");
  if (myEnv == null || EMPTY_STRING.equals(myEnv))
  {
    // warning emitted to SystemOut.log indicating defaulting to dev
    myEnv = "dev";
  }

  String propertiesFile = "/" + myEnv + "_" + propertiesFileName;
  InputStream in = this.getClass().getResourceAsStream(propertiesFile);
  if (in == null)
  {
    // warning emitted to SystemOut.log regarding no properties file
    // in classpath
  } else
  {
    try
    {
      configProperties = new Properties();
      configProperties.load(in);

    } catch (Exception e)
    {
      // exception emitted to SystemOut.log
    }
  }

  return configProperties;
}

4. initUserIdAndPassword method

The initUserIdAndPassword method reads a Username and Password property, decodes the values, and sets the _appUsername and _appPassword instance variables of the class. Given the way the handler method works, the _appUsername and _appPassword take on the role of default username and password for the client application.

Listing 4. initUserIdAndPassword method
private void initUserIdAndPassword(Properties configProperties)
{
  String encodedUsername = null;
  String encodedPassword = null;
 
  if (configProperties != null)
  {
    encodedUsername = configProperties.getProperty("Username");
    if (encodedUsername == null)
    {
      // warning emitted to SystemOut.log
    } else
    {
      this._appUsername = decode(encodedUsername);
    }
      
    encodedPassword = configProperties.getProperty("Password");
    if (encodedPassword == null)
    {
      // warning emitted to SystemOut.log
    } else
    {
      this._appPassword = decode(encodedPassword).toCharArray();
    }
  }
}

// decode helper method uses Apache commons Base64
private String decode(String str)
{
  return new String(Base64.decodeBase64(str.getBytes()));
}

5. setThreadIdentity method

The setThreadIdentity method is used in the body of the main client code before the invocation of a service request that requires a specific username and password for that given request. The source of the identity would be specific to the client application; for example, the application gets a username and password from a user or from some other source. In this article, the assumption is that there is not a trust relationship set up between the client and service provider, so a username and password are needed in the UsernameToken for the request to be accepted by the provider.

Listing 5. setThreadIdentity method
public static void setThreadIdentity(String userId, char[] pw)
{
  username.set(userId);
  password.set(pw);
}

The code sample below, from the sample client application, requires the user to provide a username and password in the HTML form that allows a customer to be deleted. This username and password are set on the thread before the deleteCustomer request is invoked. (Parameter validation code has been removed from the code sample shown here.)

Listing 6. Code sample with username and password set in HTML
String customerId = request.getParameter("customerId");
String username = request.getParameter("username");
String password = request.getParameter("password");

ClientIdCallbackHandler.
      setThreadIdentity(username,password.toCharArray());
crmService.deleteCustomer(customerId);

6. handle method

The most interesting method of the ClientIdCallbackHandler is the handle method, which is invoked by the WebSphere Application Server runtime on each service invocation in order to set the username and password that the container is to use for the UsernameToken that it creates for the outgoing service request.

Listing 7. handle method
public void handle(Callback[] callbacks) throws IOException,
      UnsupportedCallbackException
{

  for (int i = 0; i < callbacks.length; i++)
  {
    if (callbacks[i] instanceof NameCallback)
    {
      // provide the username, using default from configuration
      // or thread specific value
      NameCallback nc = (NameCallback) callbacks[i];
      String user = (String) username.get();
      if (user == null)
        if (this._appUsername != null)
          user = this._appUsername; // from properties file
        else
          user = this._wasUsername; // from WAS container

      nc.setName(user);

      // after each use of thread local username,
      // revert to using defaults
      username.set(null);
      
    } else if (callbacks[i] instanceof PasswordCallback)
    {

      // provide the password, using default from configuration
      // or thread specific value
      PasswordCallback pc = (PasswordCallback) callbacks[i];
      char[] pw = (char[]) password.get();
      if (pw == null)
        if (this._appPassword != null)
          pw = this._appPassword; // from properties file
        else
          pw = this._wasPassword; // from WAS container

      pc.setPassword(pw);

      // also, after each use revert to using default
      password.set(null);
      
    } else if (callbacks[i] instanceof PropertyCallback)
    {
      PropertyCallback pc = (PropertyCallback) callbacks[i];
      pc.setProperties(_properties);
    } else
    {
      throw new UnsupportedCallbackException(callbacks[i], callbacks[i]
            .getClass()
            + " - Unrecognized Callback");
    }
  } // for
}

Configuring ClientIdCallbackHandler

The ClientIdCallbackHandler and its supporting classes are in their own Java project. This makes it convenient to include it with any Web services client application. The steps are described here as generally as possible. Screen images from Rational Application Developer V6.0 are used to illustrate the description. All development work described here was performed in a J2EE™ perspective, in the Project Explorer view. You will see specific artifact names in the screen images related to the demonstration application that is provided in the download file included with this article.

The demo application is a pseudo Customer Relationship Manager (CRM) application that is exposed as a Web service. The client enterprise application that invokes the CRM service provider is named CRMWebServiceClientApp. The client application has a Web module named CRMWebServiceClient that holds the (WSDL2Java) generated stub and helper classes from the WSDL definition of the CRM service. The CRMWebServiceClient also has a servlet and some JSPs that implement a very simple Web application that uses the CRM service. The CRM service supports the CRUD operations on a database of customers and their billing and shipping addresses.

In the following configuration steps, the overall objective of a step is described first, followed by details that explain what needs to be done to complete that objective.

  1. Include the ClientIdCallbackHandler Java project as a project utility JAR in the parent Web service client application:

    1. Open the application deployment descriptor for the enterprise application (for example, CRMWebServiceClientApp) and select the Module tab.
    2. Under the Project Utility JARs section, click the Add button.
    3. Select ClientIdCallbackHandler from the pop-up dialog and click OK.
    4. Now, ClientIdCallbackHandler appears as one of the application's utiltity JARs (Figure 1). Save the changes and close the deployment descriptor.
    Figure 1. Add ClientIdCallbackHandler.jar to Project Utility JARs of the Web service client application
    Figure 1. Add ClientIdCallbackHandler.jar to Project Utility JARs of the Web service client application
  2. Add the ClientIdCallbackHandler to the Java JAR Dependencies for the module that is implementing the Web service client (for example, the Web module CRMWebServiceClient):

    1. Right-click on the module and select Properties.
    2. Select Java JAR Dependencies.
    3. Check ClientIdCallbackHandler.jar, and that it displays in the Manifest Class-Path for the module (Figure 2). Click OK.
    Figure 2. Add ClientIdCallbackHandler.jar to Web module Java JAR dependencies
    Figure 2. Add ClientIdCallbackHandler.jar to Web module Java JAR dependencies
  3. Modify the Web service client deployment descriptor Request Generator Configuration to use UsernameToken authentication:

    1. Open the deployment descriptor editor for your Web service client implementation module (for example, CRMWebServiceClient). Double-clicking on the module deployment descriptor icon or the deployment descriptor artifact (web.xml or ejb-jar.xml) will open the appropriate editor.
    2. In the deployment descriptor, the WS Extension and WS Binding tabs are used to configure WS-security. Click on the WS Extension tab.
    3. Expand the Request Generator Configuration item in the right column.
    4. Expand the Security Token item.
    5. If you have more than one service used by a client, you might need to select the service you are configuring under Port QName Bindings in the left column (for example, CustomerManagerService).
    6. Click the Add button associated with the Security Token item (Figure 3).
      Figure 3. Add the security token definition
      Figure 3. Add the security token definition
    7. In the Security Token dialog, enter or select the following values (Figure 4):
      • Name: any descriptive name; for example, crmclient_username_token
      • Token type: Username
      • URI: leave default value
      • Local name: value is filled in automatically.
      Figure 4. Security token definition dialog
      Figure 4. Security token definition dialog
    8. Click OK to complete the definition of the security token.
      Figure 5. Security token definition added
      Figure 5. Security token definition added
  4. Modify the client deployment descriptor WS bindings to add the callback handler that will provide the username and password for the UsernameToken that gets added to the header of the service request:

    1. Click on the WS Binding tab of the deployment descriptor.
    2. Expand Security Request Generator Binding Configuration in the right column.
    3. Expand the Token Generator item.
    4. Again, if you have more than one service reference in your client application, choose the relevant one in the Service references item in the left column. In the sample application, there is only one service reference (service/CustomerManagerService).
    5. Click on the Add button associated with the Token Generator item (Figure 6).
      Figure 6. Add the security token generator binding
      Figure 6. Add the security token generator binding
    6. In the token generator dialog, enter or select the following values (Figure 7):
      • Token generator name: any desciptive name; for example, crmclient_username_token_generator
      • Token generator class: UsernameTokenGenerator
      • Security token: Select the one you just defined under the WS Extension tab; for example, crmclient_username_token.
      • Check Use value type.
      • Value type: Username Token
      • The Local name is automatically filled in.
      • Call back handler: com.ibm.issw.ws.client.handlers.ClientIdCallbackHandler
      You can leave the User ID and Password fields empty if you are planning on supplying a default in the configuration properties file as the sample application does. (For initial testing in a development environment, you would tend to fill in values for User ID and Password.) Leave empty values for the remainder of the attributes.
      Figure 7. Security token generator binding dialog
      Figure 7. Security token generator binding dialog
    7. Click OK to complete the definition of the token generator.
      Figure 8: Completed token generator binding
      Figure 8: Completed token generator binding
  5. Save the deployment descriptor for the Web service client implementation module.

More client configuration details

This section describes additional client side configuration elements that you need to set up in order to get the ClientIdCallbackHandler and your application working properly.

Login properties files for each deployment environment

In the example scenario, you want to be able to use a different username and password for each of four possible deployment environments. A "properties" folder has been placed in the root of the Web service client enterprise application, called CRMWebServiceClientApp, containing dev_login.properties, test_login.properties, qa_login.properties and prod_login.properties files.

Figure 9. Login properties files for each deployment environment added to the enterprise application
Figure 9. Login properties files for each deployment environment added to the enterprise application
  1. Add the properties folder to the manifest classpath of the implementation module; for example, CRMWebServiceClient (this requires editing manifest.mf with a text editor rather than through the module properties Java JAR dependencies editor):

    1. Navigate to the MANIFEST.MF file in the implementation module (Figure 10).
      Figure 10. Navigate to the MANIFEST.MF file in a Web module
      Figure 10. Navigate to the MANIFEST.MF file in a Web module
    2. Right-click on MANIFEST.MF and select Open With => Text Editor.
    3. Add the entries as shown in Figure 11. Be careful to ensure that there are two spaces separating each entry. In the sample shown, there is a space character at the end of each line (except the last one), and one at the beginning of each of the last three lines. The line length limit in MANIFEST.MF files is 72 characters. (The entry that includes the parent project name in the path is needed to enable the classloader to find the properties folder in the Rational Application Developer unit test environment.)
      Figure 11. Use a text editor to make changes to the MANIFEST.MF file
      Figure 11. Use a text editor to make changes to the MANIFEST.MF file
    4. You can check to make sure that the manifest classpath will be read properly by opening up the module properties and looking in the Java JAR dependencies. If you didn't get the proper separation between entries in the classpath, you will be able to see any problems in this view.
  2. The username and password in each of the login.properties files is base64 encoded. The sample application includes a simple program you can run to encode a given input string. To encode a username:
    1. In Other Projects, navigate to Base64Encode.java.
      Figure 12. Base64Encode program to encode login properties
      Figure 12. Base64Encode program to encode login properties
    2. Right-click on Base64Encode.java and select Run => Java Application.
    3. When the Console view prompts for a string to encode, enter a username.
    4. Paste the result into the Username value in the appropriate login.properties file.
    Repeat these steps to encode a password.
    Figure 13. Base64 encoding of a username to be pasted into a login properties file
    Figure 13. Base64 encoding of a username to be pasted into a login properties file
    Figure 14. Base64 encoded username and password in a login.properties file
    Figure 14. Base64 encoded username and password in a login.properties file

Set the JVM deployment.environment custom property

The ClientIdCallbackHandler looks at the value of a JVM system property named deployment.environment to determine which login.properties file to use. To set the JVM custom property deployment.environment to an appropriate value:

  1. From the administrative console, open Application Servers => your_server => Process Definition => Java Virtual Machine => Custom Properties and click the New button.
  2. Enter or select the following values:
    • Name: deployment.environment
    • Value: either dev, test, qa, or prod (this value is treated as prefix to the filename "login.properties" so you can use whatever values you like as long as you are consistent)
    • Description: Enter a descriptive reminder of what this custom property means.
  3. Click OK and save your changes.
  4. Restart the application server to put this change into effect.
    Figure 15. Set the deployment.environment custom property on the applicaton server JVM
    Figure 15. Set the deployment.environment custom property on the applicaton server JVM

Provider side registry entries

The usernames have been added to the security registry in use by the service provider. In the simple case of a development environment test server, the WebSphere sample file registry was used. An entry was added to the registry for each deployment environment to reflect the usernames and passwords used in the login.properties files on the client side.

Listing 8. Provider side registry entries
#Users file registry entries:
devuser:password1:207:406:"Development User"
testuser:password1:208:406:"Test User"
qauser:password1:209:406:"QA User"
produser:password1:210:406:"Production User"

In the sample application, no J2EE roles are defined, and any Web service authenticated user can use the service provider application. A more realistic application would have J2EE roles defined and mapped to groups in the security registry. A more realistic deployment would use an LDAP registry for authentication and user and group management.

Check the service endpoint URL used by the client

In the sample application, the URL in the CustomerManagerService.wsdl is http://localhost:9080/CRMWebServiceRouter/service/CustomerManagerService. To modify the hostname and port number, open the WSDL file with the WSDL editor, and drill down on the services until you get to the SOAP address.

Figure 16. SOAP address binding attribute of the service definition in the WSDL file
Figure 16. SOAP address binding attribute of the service definition in the WSDL file

The location property with the URL is in the Properties view below the main WSDL editor pane.

Figure 17. Location property of the soap:address is the default service endpoint binding
Figure 17. Location property of the soap:address is the default service endpoint binding

It is also possible to set the service endpoint at run time using the setEndpoint() method on the PortTypeProxy that gets generated for the Web service client. For example, in the init() method of a Web service client servlet, you could set the endpoint for the service proxy. This tends to be more flexible than using what is in the client WSDL file. (A robust solution to managing service endpoint binding can be found in the WebSphere Service Registry and Repository.)

In a more realistic configuration, the service provider would be using HTTPS. Configuration of SSL for a Web service client is described in the developerWorks article referenced earlier.

Provider-side configuration

This article does not address the configuration needed on the service provider for UsernameToken security, but the a detailed description of how to configure UsernameToken security on the service provider can be found in the article by Irina Singh.


Conclusion

This article described a custom JAAS callback handler that enables a Web service client program to dynamically set the username and password when using Web Services UsernameToken authentication. You learned how to configure the callback handler for a Web services client in WebSphere Application Server V6.0, with a complete working example containing full source code. We hope you find this useful as you develop your Web services projects.


Download

DescriptionNameSize
Sample applicationClientIDCallbackHandlerSampleApplication-v1.1.zip1.4 MB

Resources

Learn

Discuss

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
ArticleID=240589
ArticleTitle=Achieve dynamic authentication in a Web services client using a custom JAAS callback handler
publish-date=07182007