This is an advanced article, and is targeted at readers who:
- Have a basic familiarity with user-centric identity technologies like Information Cards and OpenID
- Are extremely competent in the deployment and configuration of Tivoli Federated Identity Manager 6.2
- Are comfortable reading and understanding XSLT mapping rules with TFIM, as the article will present custom mapping rules which leverage TFIM-provided API's for reading and storing aliases
The article will help instruct you to perform TFIM configuration tasks with high-level directions, such as creating federations, updating mapping rules, etc. If this is not familiar terminology, you may need to seek basic training in Tivoli Federated Identity Manager before trying to implement the techniques described in this article.
Risks and requirements for adoption
The solution allows for the replacement of password authentication (or any other authentication method) with authentication via a credential issued by an identity provider selected by the user. The system can always enforce some restrictions on the set of identity providers, however allowing the user to select their own, or in the case of information cards using a self-issued card, provides for the greatest convenience and flexibility for users. This flexibility also has risks to the user's account data as the security of authentication to any user-centric enabled site becomes only as secure as the means of authentication to the issuer of the user-centric credential. Provided the business can accept this risk, or transfer the risk to the consumer (which is a large "if"), and the consumer is careful in their selection of an identity provider (particularly for OpenID), the model provides a very convenient way for consumers to replace their password-based authentications with a federated single sign-on using an identity provider of their choice.
The solution as presented uses Tivoli Federated Identity Manager 6.2 for processing user-centric credentials. Consequently the environments to which the solution applies are restricted to those authentication environments integrated with TFIM. Out-of-the-box this includes Tivoli Access Manager and environments supporting LTPA authentication such as WebSphere and Domino, plus other environments which have TFIM integration such as ASP.NET.
The solution described by this article makes use of Tivoli Federated Identity Manager 6.2 support for Information Card and OpenID technology, although the fundamental design principals are not product-specific. At a high level, Figure 1 presents user-interaction diagram which describes bootstrapping the user-centric authentication process:
Figure 1. Linking a user-centric authentication credential to an existing account
When an unauthenticated user later visits the site and is prompted for login, they may present their user-centric credential as a means of authentication. The unique, security-related alias associated with that credential is used to "lookup" the linked user id and log the user in.
There is some processing logic to be applied when a user presents a user-centric credential, and that logic is best explained with the following flowchart which would apply during either the linking process, or an attempt to authenticate after linking.
Figure 2. Processing a user-centric credential for authentication or linking to an existing account
Note that in the above diagram while self-registration is outside the scope of this article, a follow-up article will cover expanding this scenario to include self-registration.
The user-centric credential alias
From the flowchart in Figure 2 you can see that a key element of linking of a user-centric credential to a user's account is the notion of a unique identifier (aka alias) which can be derived from the user-centric credential. One key concept with user-centric credentials is that the relying-party site (i.e. our website which is receiving these credentials) doesn't need to trust where the credential comes from, only that there is only one user who can successfully present the credential in a secure way, and that this same user can re-present the same credential in the future. This differs from a password only in that the user interacts with a 3rd-party identity provider to authenticate, and the relying-party can securely determine that the user has done this. There is no need for a "trust relationship" between the relying-party and the issuer of the user-centric credential. This is quite a different model to traditional federated single sign-on protocols like Liberty and SAML which require out-of-band sharing of secret key and endpoint information, and allows for a more distributed, rapid-adoption deployment of cross-web-domain single sign-on technology.
In this article we demonstrate two types of user-centric credentials - Information Card and OpenID. In each case however it's necessary to establish a "unique identifier" which can be used as the alias to link to the user's account. The choice for the unique alias is shown in the following table:
Table 1. Unique alias values for user-centric credentials
|User-Centric Technology||Alias Value|
|Information Card||The alias to be used will be the uniqueid attribute provided by Tivoli Federated Identity Manager after an Information Card login has been processed. This uniqueid is a cryptographic hash of the Private Personal Identifier (PPID) of the card with the public key of the issuer who presented it. The uniqueid attribute is specifically designed by TFIM for this purpose.|
|OpenID||The alias to be used will be the claimed identifier that the relying party discovers from the user-supplied identity that end-user types into the OpenID login form.|
The mapping rule
For the purposes of this article we are going to further refine the flowchart described in Figure 2 to restrict a user to at most one alias at a time. This simplifies the mapping rule a little, and allows for easier debugging and tracking of which users own which aliases.
This article will provide working examples of a mapping rule that implements linking of an alias to a user in both XSLT and Java. These mapping rules will be functionally identical, the only difference will be the implementation strategy (and how they are configured into the STS trust chain). The article will describe the XSLT mapping rule implementation in detail, and the Java™ mapping rule implementation will be provided in the downloads section for interested developers to use or modify.
TFIM 6.2 introduces several extension functions for customers to use in either XSLT mapping rules, or in custom Java plug-ins that might be written for mapping or token manipulation. In the mapping rule we will make use of the following extension functions:
- lookupUserFromAlias: to determine if a presented alias is currently linked to a known user account
- removeAliasForUser: to remove an alias from a user
account. This is used in two cases:
- To remove an alias from an existing user if a new user is now adopting that alias
- To remove an alias from an existing user if that user is adopting a new alias
- lookupAliasesForUserAsDelimitedString: to determine if a user account has an existing alias attached to it. This is needed because there is no "replaceAlias" function, and to enforce the at-most-one-alias-per-user policy we need to check if a user has any existing alias before adding a new alias for that user.
- addAliasForUser: to add an alias to an existing user account
- throwSTSException: if an error case is detected (including an unauthenticated user presenting an alias that is not linked to a known user account)
Listing 1 presents the entire XSLT mapping rule, with full error handling, used for this demonstration. This implements the logic shown in Figure 2 with the addition of the policy that a user may have at most one alias at a time.
Listing 1. XSLT mapping rule for user-centric aliases
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:stsuuser="urn:ibm:names:ITFIM:1.0:stsuuser" xmlns:fimqs="urn:ibm:names:ITFIM:queryservice" xmlns:fimsaml="urn:ibm:names:ITFIM:saml" xmlns:fimopenid="urn:ibm:names:ITFIM:openid" xmlns:mapping-ext="com.tivoli.am.fim.trustserver.sts.utilities.IDMappingExtUtils" extension-element-prefixes="mapping-ext" version="1.0"> <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:copy> <xsl:apply-templates select="@* | node()" /> </xsl:copy> </xsl:template> <!-- Name of the federation context we will 'alias' to. Note that in this demo, we have ONE federation name shared regardless of whether you are allowing users to link OpenID's, InfoCards or both. The mapping rule is implemented so that a user can have at MOST ONE alias, regardless of what type of alias that is. To say that another way, this rule enforces that only one OpenID OR one InfoCard can be linked to an account at the time. It is possible to write the rule for multiple aliases, and for different federation names for OpenID vs InfoCard, however for the purposes of this demo we have chosen the single-alias-at-a-time approach described above. --> <xsl:variable name="fedCtx" select="'myfedctx'" /> <!-- Use either 'OpenID' or 'InfoCard' as the fedType, and the rest should work from that. We make a smart determination of the fed type from the claims type found in the STSUU. --> <xsl:variable name="fedType"> <xsl:choose> <xsl:when test="//fimopenid:OpenIDClaims">OpenID</xsl:when> <xsl:otherwise>InfoCard</xsl:otherwise> </xsl:choose> </xsl:variable> <!-- The alias to be stored in the alias service. For OpenID this is the claimed identifier. For InfoCard it's the uniqueid attribute supplied by TFIM after validation of an InfoCard token. --> <xsl:variable name="alias"> <xsl:choose> <xsl:when test="$fedType = 'OpenID'"> <!-- using OpenID - alias is the claimed identifier --> <xsl:value-of select="//stsuuser:Principal/stsuuser:Attribute[@name='name']/stsuuser:Value" /> </xsl:when> <xsl:otherwise> <!-- using InfoCard - alias is the uniqueid --> <xsl:value-of select= "//stsuuser:AttributeList/stsuuser:Attribute[@name='uniqueid']/stsuuser:Value" /> </xsl:otherwise> </xsl:choose> </xsl:variable> <!-- Name of user the alias is currently linked to --> <xsl:variable name="linkedUser" select="mapping-ext:lookupUserFromAlias($fedCtx, $alias)" /> <!-- Name of the currently logged-in user --> <xsl:variable name="authenticatedUser"> <xsl:choose> <xsl:when test="$fedType = 'OpenID'"> <!-- using OpenID --> <xsl:value-of select="//fimopenid:OpenIDClaims/fimopenid:PrincipalName" /> </xsl:when> <xsl:otherwise> <!-- using InfoCard - alias is the uniqueid --> <xsl:value-of select="//fimsaml:SAMLClaims/fimsaml:PrincipalName" /> </xsl:otherwise> </xsl:choose> </xsl:variable> <!-- This template replaces the entire Principal, applying the alias processing rules to either link the alias to an existing account, or login as a user who is linked with the provided alias. --> <xsl:template match="//stsuuser:Principal"> <stsuuser:Principal> <stsuuser:Attribute type="urn:ibm:names:ITFIM:5.1:accessmanager" name="name"> <stsuuser:Value> <xsl:choose> <!-- Determine if we have an existing user linked to the alias --> <xsl:when test="string-length($linkedUser) > 0"> <xsl:choose> <xsl:when test="string-length($authenticatedUser) > 0"> <!-- We will always stay logged in as the authenticatedUser in this case, the only thing we need to determine is if the linked user is different from the authenticatedUser. If they are different, we need to unlink from the existing linked user, and link to the authenticated user. We also need to remove any existing alias from the authenticated user to ensure the authenticated user has at most one alias at a time (that's what this demo's policy is). --> <xsl:if test="not($linkedUser = $authenticatedUser)"> <!-- Unlink alias from existing linked user --> <xsl:variable name="unlinkResult" select="mapping-ext:removeAliasForUser( $fedCtx, $linkedUser, $alias)" /> <xsl:if test="not($unlinkResult = 'true')"> <xsl:variable name="error" select="concat( 'Failed to unlink alias: ', $alias, ' from existing user: ', $linkedUser)" /> <xsl:value-of select="mapping-ext:throwSTSException($error)" /> </xsl:if> <!-- Determine if currently authenticated user has an alias, and remove it if they do. --> <xsl:variable name="existingAlias" select="mapping-ext:lookupAliasesForUserAsDelimitedString( $fedCtx, $authenticatedUser, ',')" /> <xsl:if test="string-length($existingAlias) > 0"> <!-- this assumes there is at most one alias, and the delimiter is therefore unused --> <xsl:variable name="unlinkResult" select="mapping-ext:removeAliasForUser( $fedCtx, $authenticatedUser, $existingAlias)" /> <xsl:if test="not($unlinkResult = 'true')"> <xsl:variable name="error" select="concat( 'Failed to unlink existing alias: ', $existingAlias, ' for authenticatedUser: ', $authenticatedUser)" /> <xsl:value-of select="mapping-ext:throwSTSException($error)" /> </xsl:if> </xsl:if> <!-- Link alias to authenticated user. --> <xsl:variable name="linkResult" select="mapping-ext:addAliasForUser( $fedCtx, $authenticatedUser, $alias)" /> <xsl:if test="not($linkResult = 'true')"> <xsl:variable name="error" select="concat( 'Failed to link alias: ', $alias, ' to user: ', $authenticatedUser)" /> <xsl:value-of select="mapping-ext:throwSTSException($error)" /> </xsl:if> </xsl:if> <!-- Stay logged in as the authenticatedUser --> <xsl:value-of select="$authenticatedUser" /> </xsl:when> <xsl:otherwise> <!-- No-one logged in, and we have a linked user. Login as that linked user. This is the normal authentication case when someone has already linked an alias. --> <xsl:value-of select="$linkedUser" /> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> <!-- No existing linked user - is someone logged in? --> <xsl:choose> <xsl:when test="string-length($authenticatedUser) > 0"> <!-- Determine if the authenticated user has any existing alias and remove it if they do. This is part of ensuring at most one alias per user. --> <xsl:variable name="existingAlias" select="mapping-ext:lookupAliasesForUserAsDelimitedString( $fedCtx, $authenticatedUser, ',')" /> <xsl:if test="string-length($existingAlias) > 0"> <!-- this assumes there is at most one alias, and the delimiter is therefore unused --> <xsl:variable name="unlinkResult" select="mapping-ext:removeAliasForUser( $fedCtx, $authenticatedUser, $existingAlias)" /> <xsl:if test="not($unlinkResult = 'true')"> <xsl:variable name="error" select="concat( 'Failed to unlink existing alias: ', $existingAlias, ' for authenticatedUser: ', $authenticatedUser)" /> <xsl:value-of select="mapping-ext:throwSTSException($error)" /> </xsl:if> </xsl:if> <!-- Link the current alias to the authenticatedUser --> <xsl:variable name="linkResult" select="mapping-ext:addAliasForUser( $fedCtx, $authenticatedUser, $alias)" /> <xsl:if test="not($linkResult = 'true')"> <xsl:variable name="error" select="concat( 'Failed to link alias: ', $alias, ' to authenticatedUser: ', $authenticatedUser)" /> <xsl:value-of select="mapping-ext:throwSTSException($error)" /> </xsl:if> <!-- Stay logged in as the authenticatedUser --> <xsl:value-of select="$authenticatedUser" /> </xsl:when> <xsl:otherwise> <!-- No-one logged in, and no linked user. This is an error for our demo, but also an opportunity to do self-registration if you are so inclined. --> <xsl:variable name="error" select="concat( 'Aborting login because alias: ', $alias, ' is not linked to any user account.')" /> <xsl:value-of select="mapping-ext:throwSTSException($error)"/> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </stsuuser:Value> </stsuuser:Attribute> </stsuuser:Principal> </xsl:template> </xsl:stylesheet>
Please see the Downloads section where you can
download a TFIM custom Java mapping module (including source) which
implements exactly the same logic as the above XSLT mapping rule. The
downloadable JAR is an OSGi bundle that can be inserted directly into your
plug-ins directory on your FIM installation
(<TFIM_install_root>/plugins) and deployed to the TFIM runtime. You
can also import the JAR as a project into Rational Application Developer
or Eclipse when configured for a TFIM plug-in development environment. For
more information on developing OSGi plug-ins for TFIM 6.2 and establishing
a TFIM plug-in development environment, please see the
developerWorks® tutorial I have co-authored on this topic.
After deploying the bundle to your runtime, follow these high-level steps to use it in your federation:developerWorks
- Create an instance of the mapping module using the TFIM Console under Configure Trust Service -> Module Instances -> Create. You should see a module type with the class name: com.tivoli.am.fim.demo.linkingmap.LinkingMap
- Navigate to your federation's properties page, scroll to the bottom, and select Change Identity Mapping Module Instance... then select your new module instance and submit the changes
- Reload configurations for the TFIM Runtime, and you should be ready to test.
Deploying the solution
This section discusses the various activities involved in deploying a solution that utilizes a linked OpenID or Information Card as an alternate means of authentication to your site.
Configuring the alias service
The mapping module makes use of extension functions which rely on the TFIM alias service, so be sure to configure the alias service for your domain using the TFIM Console: Domain Management -> Alias Service Settings. If you are using the XSLT mapping rule and the JDBC alias service you will need fixpack 1 or later for TFIM 6.2 as there is a known issue calling the IDMappingExtUtils functions with the JDBC alias service from XSLT. If using the LDAP alias service, or the custom Java mapping module, fixpack 1 or later is not a requirement.
Configuring your Federation(s)
Create your OpenID and/or Information Card relying party federation using the TFIM console, and use the example mapping rule shown in Listing 1 as the mapping rule for the configuration, or alternatively use an instance of the Java mapping module available in the Downloads section.
Make sure you also configure the TAM policy if you are using a TAM point of contact.
Web site and TFIM page customizations
You will need to modify your site for the following purposes:
- Provide a page for authenticated users to link an OpenID and/or Information Card to their account for future authentication. Ideally this page should also show any currently linked alias.
- Modify the login page for the site to allow users who have established an alias to login via their OpenID and/or Information Card.
For testing purposes, you can just switch to the TFIM Install/Verification Test Application (itfim-ivtapp.ear) to perform OpenID or Information Card authentications when necessary, however this does not provide the user experience you need for end-users.
As part of meeting these requirements we will build an "enablement" J2EE™ application using JSPs which is supplemental to our environment. This application is available as a download in the Downloads section called linkingenablement.zip. Unzip this file to find linkingenablement.ear which can be installed on your application server. If you choose to use this application, install it on a WebSphere application server (this can be the same server as the TFIM runtime) and junction behind WebSEAL if using a TAM point of contact.
The first page we will build is a welcome page for authenticated users which will display a menu inviting them to view their existing alias, or link an OpenID or Information Card to their account. As this is a page for authenticated users, it should be protected with a J2EE security constraint or TAM ACL depending on your point-of-contact settings. The welcome page looks like that depicted in Figure 3:
Figure 3. Welcome page for authenticated users
Alias Delegate Information
TFIM provides a built-in delegate URL for displaying and allowing a user
to remove aliases linked in the alias service. This URL is at the TFIM
/sps/alias. The View your alias link in our
welcome page points to this alias delegate. The alias
delegate takes a partner parameter as an argument (via
GET or POST). This partner parameter corresponds to the federation context
used when storing the alias, and the page will display the aliases for
that partner along with links to remove the aliases. For the example
environment, which uses TAM as a point-of-contact, the full URL to the
alias service looks like:
The page is customizable in TFIM, and replacement macros control the variable portions of the page. The standard page supports multiple aliases per partner, although in our demonstration we have coded the mapping rule to restrict a user to one alias at a time. The default page template for the alias delegate can be found at
<FIM_install_root>/pages/C/alias/alias.html, and is
show in Listing 2:
Listing 2. Default alias delegate page
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>Alias Manager</title> </head> <body> <p /> Associated aliases for @USERNAME@:<br /> <table border="1"> <tr><td>Partner</td><td>Alias</td><td>Action</td></tr> [RPT aliasEntry] <tr> <td>@PARTNER_ID@</td> <td>@ALIAS_ID@</td> <td> <a href="@ALIASMANAGER_URL@?action=remove&alias=@URLALIAS@&username=@USERNAME@">Remove</a> </td> </tr> [ERPT aliasEntry] </table> </body> </html>
You can see special tags [RPT aliasEntry] and [ERPT aliasEntry] in the page. These tags delimit a "repeatable block", which will be duplicated once for each alias for a given partner id. In this way if a user had more than one alias associated with a given partner id, multiple rows would be shown in the table. In our example mapping rules, we should only ever see one row. The various replacement macros available are described in Table 1:
Table 2. Replacement macros for alias.html
|@USERNAME@||This is replaced with the username of the currently authenticated user. It can appear either inside or outside the [RPT aliasEntry] / [ERPT aliasEntry] block.|
|@ALIASMANAGER_URL@||This is replaced with the URL of the alias endpoint. It can appear either inside or outside the [RPT aliasEntry] / [ERPT aliasEntry] block and is used to generate links for removing aliases.|
|@PARTNER_ID@||This macro belongs inside a [RPT aliasEntry] / [ERPT aliasEntry] block, and will be replaced with a federation context id for one of the aliases associated with the user.|
|@ALIAS_ID@||This macro belongs inside a [RPT aliasEntry] / [ERPT aliasEntry] block, and will be replaced with one of the aliases associated with the user.|
|@URLALIAS@||This macro belongs inside a [RPT aliasEntry] / [ERPT aliasEntry] block, and will be replaced with the URL-encoded version of the string "@PARTNER_ID%@ALIAS_ID@" for the alias being displayed. This value is used in the generation of URL's for removing aliases.|
Figure 4 shows a screenshot of an example alias page where the user has linked an Information Card to their account:
Figure 4. Example alias page
Linking Source for Information Card and OpenID
The remaining options in the
welcome.jsp show a login link for an information card and a
similar login link for an OpenID.
The JSP source for prompting for an information card is shown in Listing 3:
Listing 3. Prompting for an information card
<form method="post" action="<%=conf.getInfocardLoginDelegate()%>"> <object name="xmlToken" id="oCard" type="application/x-informationCard"> <param value="urn:oasis:names:tc:SAML:1.0:assertion" name="tokenType"> <param value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" name="requiredClaims"> </object> <input name="TARGET" type="hidden" value="<%=conf.getLinkLandingPage()%>"> <img height="16" width="23" src="infocard_23x16.png"> <input value="[Link an Information Card]" class="submitLink" type="submit"> </form>
The JSP source for prompting for an OpenID is shown in Listing 4:
Listing 4. Prompting for an OpenID
<form method="post" action="<%=conf.getOpenIDLoginDelegate()%>"> <input value="checkid_setup" name="openid.mode" type="hidden"> <input name="TARGET" type="hidden" value="<%=conf.getLinkLandingPage()%>"> <input name="openid_identifier" class="openid" type="text"> <input value="Link an OpenID" type="submit"> </form>
Configuration of the Enablement Application
The linkingenablement.ear application contains an embedded configuration file called linkingenablement.properties that you can manually edit after the application is deployed. It has self-describing properties, as shown in Listing 5:
Listing 5. linkingenablement.properties
# The alias delegate on the TFIM runtime aliasDelegate=https://www.ibmidentitydemo.com/FIM/sps/alias # The federation context id used in your mapping rule fedContext=myfedctx # The login delegate URL for your infocard login delegate. # Comment this out if you don't have an information card endpoint infocardLoginDelegate=https://www.ibmidentitydemo.com/FIM/sps/infocardsp/infocard/login # The login delegate URL for your infocard login delegate. # Comment this out if you don't have an OpenID endpoint openidLoginDelegate=https://www.ibmidentitydemo.com/FIM/sps/openidsp/openid/login # A page to land on after either an information card or openid linking operation linkLandingPage=https://www.ibmidentitydemo.com/FIM/LinkingEnablement/linklanding.jsp
Update your login page
The final step in this customization is to modify your login page (e.g., TAM login page, or the formlogin.html if you are using WebSphere for point of contact. The login form should be modified to contain an Information Card login prompt (similar to that shown in OpenID login prompt (similar to that shown in include different required or optional claims or sreg extension attributes in your login form (depending on application requirements). The linking operation doesn't require any special claims other than the PPID for an information card, and as such the templates shown in the listings above don't prompt for them. An example of what your new login page might look like is shown in Figure 5:
Figure 5. Example login page
You will find a copy of the WebSEAL login.html used to generate the above page embedded as part of the linkingenablement.ear application.
Testing the solution
To test the solution you should at first install and use the TFIM IVT Application (itfim-ivtapp.ear) that ships with the TFIM installation. This is a very valuable application for displaying and invoking your federations.
When debugging the mapping rules, use the WebSphere tracing facility. To
enable this, use the WebSphere console and navigate to:
Troubleshooting -> Logs and Trace -> server1 -> Change log level details.
Add the trace string: com.tivoli.am.fim.trustserver.sts.utilities.IDMappingExtUtils=all
If you are using the Java mapping rule, also add the trace string: com.tivoli.am.fim.demo.*=all
Test a variety of conditions, including:
- Start unauthenticated, and login using an unlinked alias (this should
be an error case and exception text thrown in the mapping rule should
appear on the error screen). Note that you could launch a
self-registration process as a result of this error, or cater for
self-registration directly in the mapping rule. A follow-on article
will present an extended solution for doing this. An example of the
error page generated for this test case by the current mapping rule is
shown in Figure 6:
Figure 6. Error page displayed when an unauthenticated user presents an unlinked alias:
- Authenticate using a username and password, then link an information card (or openid) and verify that an alias is established by looking at the alias page. You should be able to see a linked alias like that shown in Figure 4.
- After the previous test, authenticate as a DIFFERENT user, but then link the same information card (or openid). Verify that the alias is established for the current user, and removed for the previous user.
- Verify that you can authenticate from the main login page using an alias that has been linked to a user account.
- Verify that an alias can be manually removed via the alias page, and that you can no longer login using that alias after it is removed.
- Verify that different user accounts can establish unique aliases and that each alias maps correctly back to the user account it was linked against.
|User-Centric XSLT Mapping Module||user_centric_linking.xsl||12KB|
|User-Centric Custom Java Mapping Module||com.tivoli.am.fim.demo.linkingmap_1.0.0.jar||12KB|
- Participate in the discussion forum.
- The Tivoli Federated Identity Manager 6.2 Documentation allows you to access and search the TFIM 6.2 documentation available in the Tivoli Software Information Center.
- The TFIM 6.2 STS Module Development Tutorial is a great place to learn about developing OSGi plug-ins for TFIM.
- Browse the technology bookstore for books on these and other technical topics.