Adding custom XML extensions to SAML 2.0 request messages

Developing a SAML extensions plug-in for Tivoli Federated Identity Manager 6.2

IBM® Tivoli® Federated Identity Manager 6.2 (TFIM) has extended existing support of the SAML 2.0 federated single sign-on protocol to include the ability to supply custom XML elements as part SAML requests or responses. This capability is exposed by way of an Open Services Gateway Initiative (OSGi) plug-in extension to the Tivoli Federated Identity Manager runtime. This article will outline how to use this extension point including sample Java™ code and instructions for deployment and testing.

Share:

Shane B. Weeden, Senior Software Engineer, IBM Tivoli

Shane WeedenShane Weeden is a senior software engineer with the IBM Tivoli Federated Identity Manager development team. He has worked in IT security since 1992, and since 2000 has been working with Tivoli Security products including Tivoli Access Manager for eBusiness and Tivoli Federated Identity Manager. Shane now divides his time between customer focused engagements and core product development activities. He holds a Bachelor of Information Technology from the University of Queensland in Australia.


developerWorks Professional author
        level

28 October 2008

Pre-requisite knowledge

This is an advanced article designed for developers who have a need to customize SAML 2.0 request or response messages with Tivoli Federated Identity Manager 6.2. Readers should:

  • Be familiar with SAML 2.0 single sign-on protocols and message formats.
  • Be comfortable with Java development.
  • Have read and worked through the TFIM 6.2 STS Module Development Tutorial
  • Have access to a TFIM 6.2 Runtime environment with a working SAML 2.0 federation.

Introduction

The SAML 2.0 protocols support a number of message types, and transport bindings for these messages. Messages are exchanged as a request / response pair, and the schema is designed such that all request messages descend from a common abstract type called the RequestAbstractType. This type is defined in the document Assertions and Protocols for the OASIS Security Assertion Markup Language (SAML) V2.0. The RequestAbstractType schema definition (and it's dependencies) are reproduced in Listing 1:

Listing 1. RequestAbstractType schema definition
<complexType name="RequestAbstractType" abstract="true">
  <sequence>
    <element ref="saml:Issuer" minOccurs="0"/>
    <element ref="ds:Signature" minOccurs="0"/>
    <element ref="samlp:Extensions" minOccurs="0"/>
  </sequence>
  <attribute name="ID" type="ID" use="required"/>
  <attribute name="Version" type="string" use="required"/>
  <attribute name="IssueInstant" type="dateTime" use="required"/>
  <attribute name="Destination" type="anyURI" use="optional"/>
  <attribute name="Consent" type="anyURI" use="optional"/>
</complexType>

<element name="Extensions" type="samlp:ExtensionsType"/>

<complexType name="ExtensionsType">
  <sequence>
    <any namespace="##other" processContents="lax" maxOccurs="unbounded"/>
  </sequence>
</complexType>

As can be seen from Listing 1, the schema provides an extension point with the samlp:Extensions element that allows arbitrary XML in a request. Due to customer demand TFIM 6.2 introduces the capability to populate the samlp:Extensions element, and that is the focus of this article. A customer may wish to do this (for example) if the partner receiving the message uses specific information in the extensions to display custom user messages, perform provisioning operations, etc. The extension point is completely open to per-federation use cases outside of the normal SAML semantics.

SAML responses derive from the StatusResponseType element (shown in Listing 2), and the schema for this element also declares a samlp:Extensions element. The same TFIM extension point can be used to populate the value of samlp:Extensions for responses. The capability is available for both Identity Provider and Service Provider federation roles. Where and how the extension capability is used is completely dependent upon the requirements of the federation and when and how the partner receiving extension information uses it.

Listing 2. StatusResponseType schema definition
<complexType name="StatusResponseType">
  <sequence>
    <element ref="saml:Issuer" minOccurs="0"/>
    <element ref="ds:Signature" minOccurs="0"/>
    <element ref="samlp:Extensions" minOccurs="0"/>
    <element ref="samlp:Status"/>
  </sequence>
  <attribute name="ID" type="ID" use="required"/>
  <attribute name="InResponseTo" type="NCName" use="optional"/>
  <attribute name="Version" type="string" use="required"/>
  <attribute name="IssueInstant" type="dateTime" use="required"/>
  <attribute name="Destination" type="anyURI" use="optional"/>
  <attribute name="Consent" type="anyURI" use="optional"/>
</complexType>

Note that TFIM 6.2 only supports the population of samlp:Extensions and does not currently provide a mechanism to consume and act upon extension elements that may be sent from partners.

The XMLExtensionProvider Interface

The com.tivoli.am.fim.xml.extension.XMLExtensionProvider interface is an integration point which allows developers to add custom XML to the samlp:Extensions element of SAML requests and responses. Complete Javadoc for the interface can be found in the <FIM_install_root>/docs/com.tivoli.am.fim.common directory of your TFIM installation. There are two methods to implement in the interface, as follows:

  • boolean init(String config)
    This interface is obviously for initialization purposes. The value of the config parameter will be XML containing configuration information for the plug-in, wrapped in a <ExtensionConfig> element. The format of the contents of the ExtensionConfig element is an XML string tied to the schema of the extension point. This schema may be extended in future releases of TFIM, however the current schema provides only the module class name of the implementation class of the extension. An example value of the config parameter is:

    <ExtensionConfig><module exposedClass="com.tivoli.am.fim.demo.saml.extension.DemoExtension" version="1.0.0"/></ExtensionConfig>
  • org.w3c.dom.Node[] getXMLMessageExtensions(XMLMessageExtensionInfo info)
    This interface is called by the TFIM Runtime whenever a SAML 2.0 Request or Response is built for a partner provided the partner has been configured to use the XMLExtensionProvider. The Deploying your Custom Extension section discusses configuration requirements. The info parameter contains a variety of contextual information about the request or response being built (see example in Listing 4), and would typically be consulted by the extension to decide whether the given request/response type is to be populated with values for samlp:Extensions. If yes, other data in the info parameter may also be used to decide how to populate the resulting Node[]. The method should return an array of Nodes (which may themselves contain other nodes). These nodes will be populated within the samlp:Extensions element. Any specific namespaces used by the returned Nodes should be declared within those nodes.

An example echo implementation

This section introduces a utility/debug implementation of the XMLExtensionProvider interface which discovers all the contextual information passed to the extension and echoes back the values in the resulting nodes. This implementation is particularly useful as a starting point for developing your own extension provider implementation. Listing 3 presents source code for the echo implementation:

Listing 3. Echo XMLExtensionProvider implementation
package com.tivoli.am.fim.demo.saml.extension;

import java.io.StringWriter;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import com.tivoli.am.fim.xml.extension.XMLMessageExtensionInfo;
import com.tivoli.am.fim.xml.extension.XMLMessageExtensionProvider;

/**
 *
 * This is a demonstration extension to the XMLMessageExtensionProvider
 * extension point in Tivoli Federated Identity Manager 6.2.
 *
 * This extension is used to add arbitrary XML nodes to SAML requests.
 *
 * The example adds all available information from the input context, plus the
 * query string element from the HTTP request. This might typically be used to
 * include runtime-specific data paramteres in a SAML sign-on request.
 *
 * @author shane
 *
 */
public class DemoExtension implements XMLMessageExtensionProvider {

  final static String CLASS = DemoExtension.class.getName();

  final static String NSURI = "urn:mynamespace";

  final static String NSPREFIX = "myns";

  final static String ELEMENT_ATTRIBUTE_LIST = "AttributeList";

  final static String ELEMENT_ATTRIBUTE = "Attribute";

  final static String ATTR_NAME = "name";

  final static String ATTR_VALUE = "value";

  Logger _log = Logger.getLogger(CLASS);

  /**
   * getXMLMessageExtensions
   *
   * This example implementation builds a simple AttributeList node which
   * echos back all of the information discovered from the provided info
   * parameter. It also includes a copy of the Query String from the current
   * request.
   */
  public Node[] getXMLMessageExtensions(XMLMessageExtensionInfo info) {
    String methodName = "getXMLMessageExtensions";
    _log.entering(CLASS, methodName);
    Node[] result = null;

    try {

      /*
       * Production extensions should pool document builders rather than
       * create every time.
       */
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder = factory.newDocumentBuilder();

      /*
       * Create an XML document to build nodes
       */
      Document document = builder.newDocument();
      Element attrlist = (Element) document.createElementNS(NSURI,
        NSPREFIX + ":" + ELEMENT_ATTRIBUTE_LIST);
      attrlist.setAttribute("xmlns:" + NSPREFIX, NSURI);
      document.appendChild(attrlist);

      /*
       * Build a node for each of the attributes we have access to, plus
       * the query string (if any). These will be simple format, like:
       *
       * <myns:AttributeList> <myns:Attribute name="attrname1"
       * value="attrvalue1" /> <myns:Attribute name="attrname2"
       * value="attrvalue2" /> </myns:AttributeList>
       *
       */
      int num_attrs = 1; // for query string at least
      List l = info.getInfoKeys();
      if (l != null && l.size() > 0) {
        num_attrs += l.size();
      }

      // first add each attribute
      for (int i = 0; i < num_attrs - 1; i++) {
        String attrname = (String) l.get(i);
        String attrvalue = (String) info.getInfoValue(attrname);
        addAttribute(document, attrlist, attrname, attrvalue);
      }

      // now the query string
      addAttribute(document, attrlist, "QueryString", info.getRequest()
        .getQueryString());

      result = new Node[1];
      result[0] = (Node) document.getDocumentElement();

      logXML("Nodes to be added", result[0]);

    } catch (ParserConfigurationException pce) {
      pce.printStackTrace();
      _log.logp(Level.FINE, CLASS, methodName, pce.getMessage());
    } finally {
      _log.exiting(CLASS, methodName);
    }

    return result;

  }

  /**
   * This implementation of init() doesn't do anything but logging.
   */
  public boolean init(String config) {
    String methodName = "init";
    _log.entering(CLASS, methodName, new Object[] { config });
    boolean result = true;
    try {
      // nothing to do for this implementation
    } finally {
      _log.exiting(CLASS, methodName, "" + result);
    }
    return result;
  }

  /**
   * Utility function to add a child Attribute element to the parent node,
   * such as:
   *
   * <em><myns:Attribute name="attrname1" value="attrvalue1" /></em>
   *
   * @param d -
   *            owner document.
   * @param parent -
   *            parent to add Attribute to.
   * @param name -
   *            name of Attribute to add.
   * @param value -
   *            value of Attribute to add.
   */
  void addAttribute(Document d, Node parent, String name, String value) {
    Element result = (Element) d.createElementNS(NSURI, NSPREFIX + ":"
      + ELEMENT_ATTRIBUTE);
    result.setAttribute(ATTR_NAME, name);
    result.setAttribute(ATTR_VALUE, value == null ? "" : value);
    parent.appendChild(result);
  }


  /**
   * A logging method for logging XML to the diagnostic trace
   *
   * @param heading
   * @param n
   */
  void logXML(String heading, Node n) {
    String methodName = "logXML";
    _log.entering(CLASS, methodName);
    try {

      boolean finestLoggable = _log.isLoggable(Level.FINEST);

      // if logging enabled, parse token to a string and log
      if (finestLoggable) {
        Transformer t = TransformerFactory.newInstance()
          .newTransformer();
        StringWriter sw = new StringWriter();
        t.transform(new DOMSource(n), new StreamResult(sw));
        String tokenStr = sw.toString();
        _log.finest(heading + tokenStr);
      }
    } catch (Throwable t) {
      // non-fatal as just logging
      t.printStackTrace();
    } finally {
      _log.exiting(CLASS, methodName);
    }
  }
}

Note that in the above Listing 3, the getXMLMessageExtensions implementation iterates over all information provided in the input info parameter, and adds an attribute for each, plus it adds an attribute for the query string parameter of the request from the browser to the TFIM endpoint. An example of the output of this module when used to build the AuthnRequest object for service-provider initiated single sign on with the browser artifact profile is shown in Listing 4:

Listing 4. Example AuthnRequest output of the echo XMLExtensionProvider implementation
<myns:AttributeList xmlns:myns="urn:mynamespace">
  <myns:Attribute name="UserName" value=""/>
  <myns:Attribute name="FederationName" value="saml20sp"/>
  <myns:Attribute name="Profile"
    value="urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser"/>
  <myns:Attribute name="Binding"
    value="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"/>
  <myns:Attribute name="ProtocolRole" value="REQUESTER"/>
  <myns:Attribute name="MsgDestination"
    value="https://www.ibmidentitydemo.com/FIM/sps/saml20ip/saml20/login"/>
  <myns:Attribute name="MsgType" value="AuthnRequest"/>
  <myns:Attribute name="SelfProviderID"
    value="https://www.ibmdemosp.com/FIM/sps/saml20sp/saml20"/>
  <myns:Attribute name="SelfName"
    value="https://www.ibmdemosp.com/FIM/sps/saml20sp/saml20"/>
  <myns:Attribute name="SelfRole" value="sp"/>
  <myns:Attribute name="PartnerProviderID"
    value="https://www.ibmidentitydemo.com/FIM/sps/saml20ip/saml20"/>
  <myns:Attribute name="PartnerName" value="ibmidentitydemo"/>
  <myns:Attribute name="PartnerRole" value="ip"/>
  <myns:Attribute name="InitialQueryString"
    value="RequestBinding=HTTPArtifact&ResponseBinding=HTTPArtifact&
      Target=https%3A%2F%2Fwww.ibmdemosp.com%2Fcgi-bin%2Fepac"/>
  <myns:Attribute name="QueryString"
    value="RequestBinding=HTTPArtifact&ResponseBinding=HTTPArtifact&
      Target=https%3A%2F%2Fwww.ibmdemosp.com%2Fcgi-bin%2Fepac"/>
</myns:AttributeList>

As you can see from Listing 4 there are several parameters available which provide information about the request being processed and runtime data. For example the MsgType parameter indicates that the message being constructed is an AuthnRequest, and the InitialQueryString parameter contains the query string attributes (including the Target URL) of the initial request to SSO. Note that there are two query string related parameters InitialQueryString and QueryString. The difference here is subtle, yet important. The InitialQueryString contains the query string of the first request from the browser to the TFIM delegate endpoint which is generating the message. This is normally what you will want to read. The QueryString parameter is the query string of the most recent browser request, which may be different. An example of when these will be different is at an Identity Provider when the request being performed is a request to sign-on, and the user is not currently authenticated, and IBM WebSphere® is being used as the point-of-contact. In this scenario the browser will be redirected after the initial request to another WebSphere URL to authenticate (via forms login), and QueryString (which will contain the query string of the parameters sent to the WebSphere authentication URL) will be different from InitialQueryString (which will contain the query string of the sso request from the initial browser request). It is almost certain that if you need to consult parameters from the query string the item you will be interested in is the InitialQueryString.

The MsgType is particularly relevant as you would normally want to branch on this value to ensure that your plug-in only populates the samlp:Extensions for the message(s) you need. Remember, the plug-in will be called for all requests and responses sent to the partner where the extension is configured. As an example, Listing 5 shows a modification you might make to the getXMLMessageExtensions method to only add extensions to AuthnRequest messages:

Listing 5. Code snippet to only add extensions to AuthnRequest messages
  ...

  // at the top of getXMLMessageExtensions
  String msgType = (String) info.getInfoValue("MsgType");
    if ( msgType == null || !msgType.equals("AuthnRequest")) {
	    return null;
  }

  ...

As you should now realize you can utilize other available parameters to detect the partner the message is related to, the transport profile in use, etc. The recommended approach is to first install and experiment with the demonstration extension provided in this article to discover the set of available data for the message type(s) you are interested in extending, then branch your code to utilize the available parameters.


Developing an XMLExtensionProvider extension

This section will guide you through the development process for creating an OSGi plug-in for TFIM which includes an implementation of an XMLExtensionProvider.

The starting point for implementation is to establish an Eclipse workspace for TFIM plug-in development. You need to be familiar with the detailed TFIM 6.2 STS Module Development Tutorial as a pre-requisite to this article. The same workspace established for that tutorial is used to develop other TFIM plug-ins, including implementations of the XMLExtensionProvider. This article will begin with instructions that assume you have a plug-in development environment established with the Target Platform pointing to the ITFIM plugins directory.

Create a new plug-in project in your IDE, as shown in Figure 1, then press Next:

Figure 1. Project wizard - create a new plug-in project
Project Wizard - Create a new Plug-in Project

Give the project a name (com.tivoli.am.fim.demo.saml.extension), and select the other options as shown in Figure 2, then press Next:

Figure 2. Project wizard - project Name
Project Wizard - Project Name

Disable the Plug-in Options as shown in Figure 3, then press Next:

Figure 3. Project wizard - project options
Project Wizard - Project Options

There is no need to use a template, so disable that as shown in Figure 4, then press Finish:

Figure 4. Project wizard - project template
Project Wizard - Project Template

You should now see the Plug-in manifest editor. Navigate to the Dependencies tab, and add the com.tivoli.am.fim.common (6.2.0.0) package as a dependency, as shown in Figure 5, the press OK:

Figure 5. Manifest editor - dependencies
Manifest Editor - Dependencies

Navigate to the extensions tab and add a new extension of type com.tivoli.am.fim.xml.extension.provider as shown in Figure 6, then press Finish:

Figure 6. Manifest editor - add an extension
Manifest Editor - Add an Extension

Set an ID and Name for the module (our example uses DemoSAMLExtension and Demo SAML Extension respectively), then right-click on the extension and define a new module as shown in Figure 7:

Figure 7. Manifest editor - add a module definition to the extension
Manifest Editor - Add a Module Definition to the Extension

Configure properties for the module definition, as follows:

  • exposedClass - This is the class name of the class we will use to implement the extension. From Listing 3 you can see this is com.tivoli.am.fim.demo.saml.extension.DemoExtension
  • version - Set this to 1.0.0

The module should look like that shown in Figure 8:

Figure 8. Manifest editor - define module parameters
Manifest Editor - Define module parameters

Save the changes at this point, then right-click on the src folder and select New -> Package as show in Figure 9:

Figure 9. New source package
New Source Package

Set the new package name to com.tivoli.am.fim.demo.saml.extension then press Finish, as shown in Figure 10:

Figure 10. Name the package
Name the Package

Add a new Class to the package called DemoExtension, and insert the source code from Listing 3. You should see a compile error (if necessary, switch to a Java perspective) indicating that the javax.servlet.http.HttpServletRequest class cannot be resolved, as shown in Figure 11:

Figure 11. Class resolution error
Class Resolution Error

This error is to be expected, and is typical of the TFIM plug-in development process. To correct it you can follow the instructions described in the TFIM 6.2 STS Module Development Tutorial, in particular the page entitled Advanced Development Considerations. To shortcut that process, here are the required steps:

  • Ensure that your com.tivoli.am.fim.sdk project includes j2ee.jar, and that the Export-Package stanza of the com.tivoli.am.fim.sdk project exports javax.servlet.http, as shown in Figure 12:
    Figure 12. Exporting javax.servlet.http from com.tivoli.am.fim.sdk
    Exporting javax.servlet.http from com.tivoli.am.fim.sdk
    Note: The com.tivoli.am.fim.osgi.connector_6.2.0.0 package already exports javax.servlet.http, so there is no need to generate a new MANIFEST.MF for the com.tivoli.am.fim.osgi.connector_6.2.0.0 plug-in.
  • Switch back to the Manifest editor for the com.tivoli.am.fim.demo.saml.extension project, and add javax.servlet.http as an imported package, as shown in Figure 13:
    Figure 13. Importing javax.servlet.http to com.tivoli.am.fim.demo.saml.extension
    Importing javax.servlet.http to com.tivoli.am.fim.demo.saml.extension
  • That *should* be enough to fix it; however, due to an anomaly in the Eclipse platform, it's likely that your project will still not compile properly. Expand your custom plug-in project in the Java or Plug-in Development perspective, and verify if the com.tivoli.am.fim.sdk project is automatically listed under your plug-in project's Plug-in Dependencies list. If com.tivoli.am.fim.sdk is not, but org.eclipse.osgi bundle is listed, you will still have compile errors in your custom plug-in, and need to perform the following trick to fix it:
    • To fix this in the Eclipse 3.3 IDE, go to Windows->Preferences->Plug-in Development->Target Platform. Uncheck org.eclipse.osgi from the list of plug-ins and click "OK".
    • To fix this in the Eclipse 3.2 IDE (including Rational Software Architect 7) go to Windows->Preferences->Plug-in Development->Target Platform. Uncheck org.eclipse.osgi from the list of plug-ins and click "Apply", then recheck the org.eclipse.osgi plug-in, and click "OK". You will have to do this again whenever you restart Eclipse 3.2.
    Your custom plug-in project's Plug-in Dependencies should now show com.tivoli.am.fim.sdk instead of org.eclipse.osgi, and your compile errors should have resolved, as shown in Figure 14:
    Figure 14. Verify com.tivoli.am.fim.sdk in dependencies
    Verify com.tivoli.am.fim.sdk in Dependencies

The development of the plug-in is now complete - all that remains is to package, deploy and test the module.


Packaging your custom extension

Now that development of the module is complete we need to package the file into a jar that can be deployed to the TFIM 6.2 environment. This is done exactly as described in the TFIM 6.2 STS Module Development Tutorial. Be particularly mindful to use the existing MANIFEST.MF from your project rather than automatically generating the MANIFEST.MF file for the jar. For the purposes of this article, we recommend exporting the project as a jar file named: com.tivoli.am.fim.demo.saml.extension_1.0.0.jar. Alternatively you can download our pre-built demo from the Downloads section of this article.


Deploying your custom extension

There are two steps to deploying the custom module:

  • Deploying the plug-in jar to the TFIM Runtime.
  • Configuring the federation partner(s) to use the module when building SAML 2.0 messages.

Deploying the plug-in jar

To deploy the jar to the ITFIM Runtime, copy the jar file to the <ITFIM_install_root>/plugins directory, then publish the plug-ins. This can be done with the console, or with the TFIM command line framework:

  • Using the TFIM Console, navigate to Domain Management -> Runtime Node Management and use the Publish Plugins operation to copy the updated plugins directory to the WebSphere configuration repository.
  • Alternatively, the wsadmin command line interface to TFIM can be used (directly or in a JACL/Jython script) with:
    wsadmin>$AdminTask manageItfimDomain {-operation publishPlugins -fimDomainName <fim_domain_name>}

Configuration federation partner(s)

The TFIM Console does not currently support updating the appropriate federation partner configuration property for custom SAML extensions. You can however use the command line interface for updating the required property, as follows:

  • Start wsadmin for the deployment manager (in a cluster environment) or application server node (in a standalone server environment) where the ITFIM Management service is installed.
  • If you are unsure of the federation name or partner name, use the following command to list all "partner configurations" in the TFIM domain:
    wsadmin>$AdminTask manageItfimPartner {-operation list -fimDomainName <fim_domain_name>}
  • Use the following TFIM command to export the federation configuration for the desired SAML 2.0 federation to a response file:
    wsadmin>$AdminTask manageItfimPartner {-operation createResponseFile -fimDomainName <fim_domain_name> -federationName <federation_name> -partnerName <partner_name> -fileId <response_file_name>}

    This will create a response file that contains all the existing federation partner properties.
  • Edit the response file, and add a new parameter named MessageExtensionModuleID which references the extenstion ID. The extension ID was defined for the extension with the Manifest Editor, as shown in Figure 7. In our example this value is DemoSAMLExtension. The actual XML to be added to the response file should look like that shown in Listing 6:

    Listing 6. New partner parameter for defining the SAML extension
      <void method="put">
       <string>MessageExtensionModuleID</string>
       <string>DemoSAMLExtension</string>
      </void>
  • Upload your modified response file with the following TFIM command:
    wsadmin>$AdminTask manageItfimPartner {-operation modify -fimDomainName <fim_domain_name> -federationName <federation_name> -partnerName <partner_name> -fileId <response_file_name>}

    Your modifications will be saved to the TFIM configuration.
  • Repeat the last three steps (creating a partner response file, editing the response file, and uploading the modifications) for each partner that you wish to use your extension with.
  • Use the TFIM Console or command line to "Reload Configurations". In the console this is done from Domain Management -> Runtime Node Management. Given that we are already using the command line for the above steps, here's the command to reload configurations from wsadmin:
    wsadmin>$AdminTask reloadItfimRuntime {-fimDomainName <fim_domain_name>}

The module is now deployed and configured for use with your TFIM federation partner(s).


Testing your custom extension

To test the custom extension, configure the following trace string for diagnostic trace in the WebSphere server where the TFIM Runtime is deployed:

*=info: com.tivoli.am.fim.demo.*=all: com.tivoli.am.fim.saml20.protocol.extension.*=all

Next, invoke a SAML 2.0 operation (such as a single sign-on) which will result in the creation of a SAML request or response message. You should be able to see details in the WebSphere trace.log similar to that shown in Listing 7 below. Note that due to formatting restrictions, the trace lines have been wrapped, however for extra readability a blank line has been inserted between each trace string.

Listing 7. Debug trace loading and executing the DemoExtension
[8/20/08 8:02:06:825 EDT] 00000033 SAML20Protoco > com.tivoli.am.fim.saml20.protocol.exte\
nsion.SAML20ProtocolMessageExtensionProviderFactory XMLMessageExtensionProvider ENTRY

[8/20/08 8:02:06:825 EDT] 00000033 SAML20Protoco 3 com.tivoli.am.fim.saml20.protocol.exte\
nsion.SAML20ProtocolMessageExtensionProviderFactory XMLMessageExtensionProvider Extension\
 ID: DemoSAMLExtension

[8/20/08 8:02:06:830 EDT] 00000033 DemoExtension > com.tivoli.am.fim.demo.saml.extension.\
DemoExtension init ENTRY <ExtensionConfig><module exposedClass="com.tivoli.am.fim.demo.sa\
ml.extension.DemoExtension" version="1.0.0"/></ExtensionConfig>

[8/20/08 8:02:06:830 EDT] 00000033 DemoExtension < com.tivoli.am.fim.demo.saml.extension.\
DemoExtension init RETURN true

[8/20/08 8:02:06:830 EDT] 00000033 SAML20Protoco < com.tivoli.am.fim.saml20.protocol.exte\
nsion.SAML20ProtocolMessageExtensionProviderFactory XMLMessageExtensionProvider RETURN co\
m.tivoli.am.fim.demo.saml.extension.DemoExtension@64386438

[8/20/08 8:02:06:830 EDT] 00000033 SAML20Protoco > com.tivoli.am.fim.saml20.protocol.exte\
nsion.SAML20ProtocolMessageExtensionProviderFactory getXMLMessageExtensionProviderInfo EN\
TRY

[8/20/08 8:02:06:832 EDT] 00000033 SAML20Protoco < com.tivoli.am.fim.saml20.protocol.exte\
nsion.SAML20ProtocolMessageExtensionProviderFactory getXMLMessageExtensionProviderInfo RE\
TURN SAML20ProtocolMessageExtensionProviderInfo [ UserName = shane
 FederationName = saml20ip
 Profile = urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser
 Binding = urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact
 ProtocolRole = REQUESTER
 MsgDestination = https://www.ibmdemosp.com/FIM/sps/saml20sp/saml20/login
 MsgType = Response
 SelfProviderID = https://www.ibmidentitydemo.com/FIM/sps/saml20ip/saml20
 SelfName = https://www.ibmidentitydemo.com/FIM/sps/saml20ip/saml20
 SelfRole = ip
 PartnerProviderID = https://www.ibmdemosp.com/FIM/sps/saml20sp/saml20
 PartnerName = www.ibmdemosp.com
 PartnerRole = sp
 InitialQueryString = RequestBinding=HTTPArtifact&PartnerId=https%3A%2F%2Fwww.ibmdemosp.c\
 om%2FFIM%2Fsps%2Fsaml20sp%2Fsaml20&Target=https%3A%2F%2Fwww.ibmidentitydemo.com%2Fcgi-bi\
 n%2Fepac
 Request = com.ibm.ws.webcontainer.srt.SRTServletRequest@23f823f8
 ]

[8/20/08 8:02:06:833 EDT] 00000033 DemoExtension > com.tivoli.am.fim.demo.saml.extension.\
DemoExtension getXMLMessageExtensions ENTRY

[8/20/08 8:02:06:837 EDT] 00000033 DemoExtension > com.tivoli.am.fim.demo.saml.extension.\
DemoExtension logXML ENTRY

[8/20/08 8:02:06:838 EDT] 00000033 DemoExtension 3   Nodes to be added<?xml version="1.0"\
 encoding="UTF-8"?><myns:AttributeList xmlns:myns="urn:mynamespace"><myns:Attribute name=\
 "UserName" value="shane"/><myns:Attribute name="FederationName" value="saml20ip"/><myns:\
 Attribute name="Profile" value="urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser"/><myns\
 :Attribute name="Binding" value="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"/><m\
 yns:Attribute name="ProtocolRole" value="REQUESTER"/><myns:Attribute name="MsgDestinatio\
 n" value="https://www.ibmdemosp.com/FIM/sps/saml20sp/saml20/login"/><myns:Attribute name\
 ="MsgType" value="Response"/><myns:Attribute name="SelfProviderID" value="https://www.ib\
 midentitydemo.com/FIM/sps/saml20ip/saml20"/><myns:Attribute name="SelfName" value="https\
 ://www.ibmidentitydemo.com/FIM/sps/saml20ip/saml20"/><myns:Attribute name="SelfRole" val\
 ue="ip"/><myns:Attribute name="PartnerProviderID" value="https://www.ibmdemosp.com/FIM/s\
 ps/saml20sp/saml20"/><myns:Attribute name="PartnerName" value="www.ibmdemosp.com"/><myns\
 :Attribute name="PartnerRole" value="sp"/><myns:Attribute name="InitialQueryString" valu\
 e="RequestBinding=HTTPArtifact&amp;PartnerId=https%3A%2F%2Fwww.ibmdemosp.com%2FFIM%2Fsps\
 %2Fsaml20sp%2Fsaml20&amp;Target=https%3A%2F%2Fwww.ibmidentitydemo.com%2Fcgi-bin%2Fepac"/\
 ><myns:Attribute name="QueryString" value="RequestBinding=HTTPArtifact&amp;PartnerId=htt\
 ps%3A%2F%2Fwww.ibmdemosp.com%2FFIM%2Fsps%2Fsaml20sp%2Fsaml20&amp;Target=https%3A%2F%2Fww\
 w.ibmidentitydemo.com%2Fcgi-bin%2Fepac"/></myns:AttributeList>

[8/20/08 8:02:06:839 EDT] 00000033 DemoExtension < com.tivoli.am.fim.demo.saml.extension.\
DemoExtension logXML RETURN

[8/20/08 8:02:06:839 EDT] 00000033 DemoExtension < com.tivoli.am.fim.demo.saml.extension.\
DemoExtension getXMLMessageExtensions RETURN

Reading the trace you can see where the TFIM Runtime loads the DemoSAMLExtension plugin, and the calls to the init and getXMLMessageExtensions methods.


Conclusion

This extension point in TFIM is rather specialized and designed for specific scenarios where customers need to insert custom XML in the samlp:Extensions element of SAML 2.0 requests and/or responses. That said, the TFIM OSGi plug-in environment provides an ideal extensibility model for this (and other) customizations, and the development techniques demonstrated in the article are portable to other types of TFIM extensions.


Download

DescriptionNameSize
DemoExtension sample implementationcom.tivoli.am.fim.demo.saml.extension_1.0.0.jar7KB

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 Tivoli (service management) on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Tivoli (service management), Security, Tivoli
ArticleID=336484
ArticleTitle=Adding custom XML extensions to SAML 2.0 request messages
publish-date=10282008