ASP.NET Authentication using LTPA and Tivoli Federated Identity Manager (TFIM)

Using TFIM to translate LTPA tokens for authentication to an ASP.NET application.



This article requires that you are familiar with Tivoli Federated Identity Manager (TFIM) Enterprise, ASP.NET security and WS-Trust. You should be comfortable with configuring a trust chain using the TFIM management console.

Lightweight Third-Party Authentication (LPTA) is an IBM-proprietary authentication technology used in WebSphere Application Server and IBM Lotus® Domino®. LTPA works by setting encrypted user authentication information into a string, and then transmitting this string between servers, which contain the keys required to decrypt it. In a Web-based environment the transmission is typically handled with a domain cookie, and in a Web services environment, the transmission is handled by wrapping the encrypted user information string in a WS-Security BinarySecurityToken and including it in a SOAP WS-Security header. The encrypted user information string (LTPA authentication credential) can then be read by other servers with the same authentication configuration. As LTPA uses symmetric key cryptography, part of the authentication configuration is configuring the same shared key. When configured, these servers can then automatically authenticate the user without prompting for login credentials.

ASP.NET applications cannot natively decrypt and use the information inside the LTPA cookies without help from an external service. In this article we show how to use IBM Tivoli Federated Identity Manager to extract the authenticated user's identity in a Web environment using domain cookies, allowing SSO between IBM WebSphere Application Server and ASP.NET web applications. This technique can be easily adapted to also serve Web Services environments.

The protocol used to allow the ASP.NET application and the TFIM server to communicate is WS-Trust. WS-Trust uses the secure messaging mechanisms of WS-Security to allow the secure exchange of tokens between different trust domains. Microsoft provides an implementation of WS-Trust for .NET as part of the Web Services Enhancements (WSE) 3.0. We have wrapped this implementation into a ".NET FIM Trust Client" in order to simplify the interface, and we have used this implementation in the article.

Solution overview

We begin with a simple ASP.NET application using form-based authentication to display information about the logged-on user and the HTTP request. The article describes how to expand the authentication capabilities of this application to include accepting an LTPA cookie generated by IBM WebSphere Application Servers in the same DNS domain.

We modify the ASP.NET application to include a new mechanism for authentication. This mechanism will receive the LTPA cookie and validate it by calling out to Tivoli Federated Identity Manager. The identity asserted in the LTPA cookie will be used to authenticate to ASP.NET.

We use a .NET TFIM Trust Client to create a WS-Trust <BinarySecurityToken> which is exchanged by the TFIM server for a <UsernameToken>. We then use the username in this returned token to set the ASP.NET authentication cookie.

Figure 1. Overall solution architecture
Architecture Diagram
Architecture Diagram
  1. The user accesses an application running on an IBM WebSphere Application Server (
  2. The WebSphere Application Server authenticates the user and sets a domain LTPA cookie for domain "". The LTPA cookie contains encrypted user information.
  3. The user then accesses an ASP.NET application running on an IIS server in the same DNS domain (
  4. The ASP.NET application uses the configured HTTP module to extract the LTPA cookie and send it to the TFIM server for validation.
  5. The TFIM server validates the LTPA token and returns a <UsernameToken> to the ASP.NET HTTP module.
  6. The ASP.NET HTTP module extracts the username from the <UsernameToken> and uses it for login

In the ASP.NET environment this authentication has the same effect as if the user had logged onto the application locally with a username and password. A session cookie is established for the user session, and the authenticated user can proceed to use the application.

This article will not cover use of the TFIM management console to configure the required trust chain. This is standard product behaviour that is a pre-requisite to this article.

Validating LTPA tokens using Tivoli Federated Identity Manager

In order to authenticate to the ASP.NET application, we need to transform the LTPA cookie into data that identifies the user. The LTPA cookie contains encrypted information, part of which is the authenticated username, therefore, we need to decrypt the cookie in order to extract this information. We use TFIM for this purpose, where the exchange is done as part of a WS-Trust token exchange operation.

Validating a token using WS-Trust involves sending the token, along with identifying information, to the TFIM Trust Service in a <RequestSecurityToken> message. The LTPA data is included as a <BinarySecurityToken>. The Trust Service is configured with the information necessary to decrypt the LTPA data, and issues a <UsernameToken> in a <RequestSecurityTokenResponse>.

Any token type can be issued from the TFIM Trust Service, not just the <UsernameToken> that we focus on in this article. For example, the Trust Service can be configured to issue SAML tokens. Tokens such as SAML allow the inclusion of user attribute information as well as authentication data, and the TFIM Trust Chain allows these attributes to be retrieved from external data sources. By using TFIM to exchange the LTPA token for a "local authentication token", user identity and attribute mapping can take place external to the application, and can be shared between multiple applications.

This article leverages a Trust Client based on WSE 3.0 that is written specifically to interoperate with TFIM. This trust client establishes a connection to the TFIM Trust Service, and handles all aspects of the WS-Trust token validation and exchange. During normal runtime operation, users of this trust client will call SendToken which takes a SecurityToken as a parameter and returns a Security Token. The TFIM Trust Client also provides an implementation of the .NET BinarySecurityToken class that we can use to create a SecurityToken containing our LTPA data.

Below is an example of the RequestSecurityToken and RequestSecurityTokenResponse, with the relevant security tokens highlighted.

Listing 1. WS-Trust message request
<wst:RequestSecurityToken xmlns:wst="">
  <wsp:AppliesTo xmlns:wsp="">
    <wsa:EndpointReference xmlns:wsa="">
    <wsu:Expires xmlns:wsu=" \
    <wsa:Address xmlns:wsa="">
    ****** REQUEST SECURITY TOKEN ******
      EncodingType=" \
      xmlns:wsu=" \
      xmlns:wsse=" \
    ****** END TOKEN ******
Listing 2. WS-Trust message response
  xmlns:wsu=" \
      xmlns:wss=" \
      xmlns:wsu=" \
        EncodingType=" \
    ****** END TOKEN ******
  <wst:RequestedAttachedReference xmlns:wss=" \
        ValueType=" \
        xmlns:wss=" \
            oasis-200401-wss-wssecurity-secext-1.0.xsd" />

Contact the authors for more information on the availability of the LTPA token module for TFIM 6.1.1.

In the returned <wss:UsernameToken> the Username parameter is returned in the form of a fully-qualified DN, exactly as it is specified in the LTPA data. This is counter-intuitive in a .NET environment, where applications typically expect an unqualified user ID. To fix this issue, we have included a custom piece of XSL in TFIM mapping that extracts the user ID from the fully-qualified DN.

Listing 3. XSL mapping module
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="" 
  version="1.0" xmlns:stsuuser="urn:ibm:names:ITFIM:1.0:stsuuser"> 
  <xsl:strip-space elements="*" /> 
  <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes" /> 
  <!--  Initially we start with a copy of the document. --> 
  <xsl:template match="@* | node()">  
      <xsl:apply-templates select="@* | node()" />
  <!--   This will prepare the principal name's type for UT issue. -->
  <xsl:template match="//stsuuser:Principal/stsuuser:Attribute[@name='name']">
    <xsl:variable name="username" 
      select="//stsuuser:Principal/stsuuser:Attribute[@name='name']/stsuuser:Value" />
    <stsuuser:Attribute name="name" type=" \
        <xsl:value-of select="substring-before(substring-after($username,'uid='),',')"/>

Once this mapping stylesheet is used, the returned UsernameToken no longer contains the fully-qualified user name.

The sample application

This article borrows the sample application from another developerWorks article on Tivoli Federated Identity Manager and .NET integration:

The sample application is a simple Web application that displays information about the current user's session. The standard ASP.NET authentication API is used to authenticate the user, and authentication is initially achieved using forms-based log in.

The LTPA authentication HTTP module

Now that we have our test application, we need to go about modifying it to accept the LTPA cookie set by an IBM WebSphere Application Server. As described above, we use the WS-Trust protocol to communicate with TFIM and exchange the encrypted LTPA string (contained in a domain cookie) for a username. We can then create a session in ASP.NET for this user. Listing 4 shows the psuedo-code representation of what we want to do in order to authenticate the user.

Listing 4. Authentication module pseudo-code
  if the request is not already authenticated
    if an LTPA cookie is set
      create a BinarySecurityToken containing the appropriate attributes and cookie data
      send the created token to the TFIM Trust Service
      extract the username from the returned token

      authenticate the user represented by "username" to ASP.NET
      specify that the ASP.NET authentication cookie for the user should be set
          in the response from IIS
      redirect the user to the currently requested location to set the authentication
          cookie in the browser
    end if
  end if

As a part of the ASP.NET architecture, HTTP modules allow third-party modules to be called at various points in the ASP.NET processing cycle (events). HTTP modules can register to be invoked at the AuthenticateRequest event. An HTTP module that registers for this event will be called when the ASP.NET environment is attempting to authenticate the user making the request. For those readers familiar with WebSphere® development, this model is very similar to the concept of WebSphere Trust Association Interceptors. We will develop an HTTP module called "FIMLTPAAuthenticationModule", which will exchange the LTPA cookie for a UsernameToken and use it to authenticate a user into ASP.NET.

Listing 5 shows the code of the finished IHttpModule implementation.

Listing 5. Authentication module implementation
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Collections;
using Microsoft.Web.Services3.Security.Tokens;
using System.Web.Security;
using IBM.Tivoli.FIM.TrustClient;
using IBM.Tivoli.FIM.TrustClient.Tokens;
using System.Diagnostics;
using Microsoft.Web.Services3.Security;
using System.Xml;
using System.Security.Principal;
using System.IO;
using System.Xml.Serialization;
using System.Configuration;

namespace IBM.Tivoli.SOA.Web
     * FIMLTPAAuthenticationModule is a class that implements the IHttpModule 
     * interface to provide LTPA authentication an ASP.NET application.  This 
     * module uses the FIM Trust Service to validate the LTPA token and 
     * exchange it for a username token.
    public class FIMLTPAAuthenticationModule : IHttpModule
        private static string MODULE_NAME = "LTPAAuthModule";
        private static string LTPA_V1_COOKIE_NAME = "LtpaToken";
        private static string LTPA_V2_COOKIE_NAME = "LtpaToken2";

        private static string LTPA_V1_TOKEN_VALUE = "wsst:LTPA";
        private static string LTPA_V2_TOKEN_VALUE = "wsst:LTPAv2";

        private static string NAMESPACE_ATTRIBUTE = "xmlns:wsst";
        private static string LTPA_V1_NAMESPACE = 
        private static string LTPA_V2_NAMESPACE = 

        private static string CONFIG_FIM_SERVER = "fimStsUrl";
        private static string CONFIG_FIM_ISSUER = "fimIssuer";
        private static string CONFIG_FIM_APPLIES_TO = "fimAppliesTo";

        FIMTrustClient trustClient;

        private XmlDocument xmlDoc = new XmlDocument();

        public FIMLTPAAuthenticationModule():base()
            string uri = System.Configuration.ConfigurationManager.AppSettings.Get(
            string issuer = System.Configuration.ConfigurationManager.AppSettings.Get(
            string appliesTo = System.Configuration.ConfigurationManager.AppSettings.Get(

            trustClient = FIMTrustClientFactory.createTrustClient(
                new Uri(uri), issuer, appliesTo); 

        #region IHttpModule Members

        public void Dispose() {  }

        public void Init(HttpApplication context)
            context.AuthenticateRequest += new EventHandler(

        public string ModuleName
                return MODULE_NAME;


        private void Application_OnAuthenticateRequest(object sender, System.EventArgs e)
            HttpApplication app = (HttpApplication)sender;
            HttpContext ctx = app.Context;

            //If we aren't already authenticated
            if (!ctx.Request.IsAuthenticated)
                SimpleBinarySecurityToken requestToken = null;

                //Extract the LTPA cookie
                HttpCookie ltpaCookie = ctx.Request.Cookies.Get(LTPA_V2_COOKIE_NAME);
                if (ltpaCookie != null)
                    //Create a binary security token.
                    requestToken = new SimpleBinarySecurityToken(LTPA_V2_TOKEN_VALUE, 
                    requestToken.setAttribute( NAMESPACE_ATTRIBUTE, LTPA_V2_NAMESPACE);
                    ltpaCookie = ctx.Request.Cookies.Get(LTPA_V1_COOKIE_NAME);
                    if (ltpaCookie != null)
                        requestToken = new SimpleBinarySecurityToken(LTPA_V1_TOKEN_VALUE, 
                            WSSecurity.EncodingTypes.Base64Encoding, ltpaCookie.Value);

                //If we have an LTPA token, then swap it for a usable token
                // using the TFIM STS
                if (ltpaCookie != null)
                    //Call TFIM
                        SecurityToken response = trustClient.SendToken(requestToken);
                        if (response != null)
                            string username = null;

                            if (response is UsernameToken)
                                UsernameToken responseToken = (UsernameToken)response;

                                //Extract the user name from the Token
                                username = responseToken.Username;

                            if (username != null)
                                //Get a string serialization of our SecurityToken
                                XmlElement tokenElem = response.GetXml(xmlDoc);
                                string serializedToken = tokenElem.OuterXml;

                                //Set our UserData to be the serialized token
                                FormsAuthenticationTicket ticket = new 
                                    FormsAuthenticationTicket(1, username, 
                                    DateTime.Now, DateTime.Now.AddHours(3), false,

                                string encryptedTicket = 

                                //Set the Forms authentication cookie
                                HttpCookie authCookie = new HttpCookie(
                                    FormsAuthentication.FormsCookieName, encryptedTicket);

                                    FormsAuthentication.GetRedirectUrl(username, false));
                    catch (FIMTrustClientException exception)
                        //Log an error, don't proceed with login
                            "An exception occurred while exchanging token. Details: "
                            + exception.Message);

Notice that as part of setting the authentication cookie, we serialize the received SecurityToken and place it in the authentication ticket. This allows the application to access the token when the user has logged in. While this is of limited usefulness when the received token is a UsernameToken, the same method can be utilized when a token containing more information (such as a SAML assertion) is returned from the Trust Service and used to authenticate to ASP.NET.

The following screenshot shows the test application after the user has logged in via an LTPA cookie. The "UserData" section contains the received SecurityToken.

Figure 2. Application post-login

Integrating the LTPA authentication HTTP module into the ASP.NET application

The next step is to integrate the LTPA HTTP module into the sample application. We recommend three steps for the enablement:

  1. Modify the application's Web.config file to use the LTPA authentication HTTP module.
  2. Configure the details for the TFIM Trust Client
  3. Bypass the default .NET user name authentication

Adding the HttpModule

The use of HTTP modules within the ASP.NET application is controlled by the httpModules configuration. This configuration section can be defined at the computer, site, or application level. The httpModules configuration defined at higher levels will be inherited by lower levels.

In our illustration, we only enable our sample application for federated single sign-on (not other applications hosted in the environment). We add the LTPA authentication module into the httpModules configuration section for the application's Web.Config only. Listing 6 shows both the httpModules configuration section and its position within the Web.Config file.

Configuring the TFIM Trust Service

In order to use the TFIM Trust Client, the HTTP module needs the following parameters:

Table 1. Configuration parameters required to pass to the TFIM Trust Client
Configuration parameterDescription
fimStsUrlThe full URL of the TFIM Trust Service, for example
fimIssuerThe <Issuer> value that the TFIM Trust Client will use for outgoing <RequestSecurityToken> messages.
fimAppliesToThe <AppliesTo> value that the TFIM Trust Client will use for outgoing <RequestSecurityToken> messages.

These values must be placed in the appSettings, with each parameter as a separate key.

Bypassing user name authentication

The default configuration of WSE 3.0 in .NET attempts to authenticate users received in UsernameToken values as part of a RequestSecurityTokenResponse. This behaviour is undesirable for our application for two reasons:

  1. We want to trust the user name returned from the TFIM Trust Service.
  2. It requires the password, or a password digest, to be present in the returned token.

In order to bypass this authentication mechanism, we provide an implementation of the UsernameTokenManager called TrustedUsernameTokenManager. This class is configured in the Web.config as per Listing 6.

Overall Web.Config

The following shows the overall layout of the Web.config file, with each of the sections outlined above.

Listing 6. Application Web.config file
<?xml version="1.0"?>
            <add namespace=" \
              type="IBM.Tivoli.FIM.TrustClient.Tokens.TrustedUsernameTokenManager, \
                  FIMTrustClient" />
        <add key="fimStsUrl" 
            value="http://[host]:[port]/TrustServer/SecurityTokenService" />
        <add key="fimAppliesTo" value="[AppliesTo]" />
        <add key="fimIssuer" value="[Issuer]" />
        <add type="IBM.Tivoli.SOA.Web.FIMLTPAAuthenticationModule, \

The syntax for adding an HTTP module into the application's configuration is <add type="[Class],[Assembly]" name="[ModuleName]" />. In Listing 5, we specified that our class was called FIMLTPAAuthenticationModule and it was defined in the IBM.Tivoli.SOA.Web namespace, therefore the [Class] we specify is IBM.Tivoli.SOA.Web.FIMLTPAAuthenticationModule. The [Assembly] is the name of the CLR assembly that our class is defined in. This is the name of the Dynamic Link Library (DLL) file that the [Class] is found in. In the sample projects, we have compiled the FIMLTPAAuthenticationModule module into the FIMLTPAAuthenticationModule.dll file, so this is the value used for the [Assembly]. When defined as part of the application configuration, the ASP.NET environment attempts to locate the assembly in the Global Assembly Cache or in the bin subdirectory of the application. Our example uses the FIM LTPA authentication module in the application's bin subdirectory.

Downloadable resources

Related topics


Sign in or register to add and subscribe to comments.

Zone=Security, Tivoli
ArticleTitle=ASP.NET Authentication using LTPA and Tivoli Federated Identity Manager (TFIM)