使用ltpa时认证失败
背景
本文要求您熟悉Tivoli Federated Identity Manager(TFIM)6.1.1.1企业版,ASP.NET安全性和WS-Trust。 您应该习惯于使用TFIM管理控制台配置信任链。
轻量级第三方认证(LPTA)是WebSphere Application Server和IBMLotus®Domino®中使用的IBM专有认证技术。 LTPA的工作方式是将加密的用户身份验证信息设置为字符串,然后在服务器之间传输此字符串,其中包含对其进行解密所需的密钥。 在基于Web的环境中,传输通常由域cookie处理,在Web服务环境中,通过将加密的用户信息字符串包装在WS-Security BinarySecurityToken
并将其包含在SOAP WS-Security标头中来处理传输。 。 然后,其他具有相同身份验证配置的服务器可以读取加密的用户信息字符串(LTPA身份验证凭据)。 由于LTPA使用对称密钥加密,所以身份验证配置的一部分是配置相同的共享密钥。 配置后,这些服务器可以自动验证用户身份,而无需提示输入登录凭据。
如果没有外部服务的帮助,ASP.NET应用程序将无法本地解密和使用LTPA cookie中的信息。 在本文中,我们展示如何使用IBM Tivoli Federated Identity Manager 6.1.1.1在Web环境中使用域cookie提取经过身份验证的用户的身份,从而允许在IBM WebSphere Application Server和ASP.NET Web应用程序之间进行SSO。 可以轻松地将此技术应用于Web服务环境。
允许ASP.NET应用程序和TFIM服务器通信的协议是WS-Trust。 WS-Trust使用WS-Security的安全消息传递机制来允许在不同信任域之间安全地交换令牌。 Microsoft作为Web服务增强(WSE)3.0的一部分提供了WS-Trust for .NET的实现。 为了简化界面,我们已将此实现包装到“ .NET FIM信任客户端”中,并且在本文中使用了此实现。
解决方案概述
我们从一个简单的ASP.NET应用程序开始,该应用程序使用基于表单的身份验证来显示有关已登录用户和HTTP请求的信息。 本文介绍了如何扩展此应用程序的认证功能,以包括接受同一DNS域中的IBM WebSphere Application Server生成的LTPA cookie。
我们修改ASP.NET应用程序以包括新的身份验证机制。 该机制将接收LTPA cookie并通过调出Tivoli Federated Identity Manager对其进行验证。 LTPA cookie中声明的身份将用于向ASP.NET进行身份验证。
我们使用.NET TFIM Trust Client创建一个WS-Trust <BinarySecurityToken>
,它由TFIM服务器交换为<UsernameToken>
。 然后,我们在此返回的令牌中使用用户名来设置ASP.NET身份验证cookie。
图1.整体解决方案架构

- 用户访问在IBM WebSphere Application Server( http://websphere.example.com )上运行的应用程序。
- WebSphere Application Server对用户进行身份验证,并为域“ example.com”设置域LTPA cookie。 LTPA cookie包含加密的用户信息。
- 然后,用户访问在同一DNS域(http://asp.example.com)上的IIS服务器上运行的ASP.NET应用程序。
- ASP.NET应用程序使用配置的HTTP模块提取LTPA cookie,并将其发送到TFIM服务器进行验证。
- TFIM服务器验证LTPA令牌,并向ASP.NET HTTP模块返回
<UsernameToken>
。 - ASP.NET HTTP模块从
<UsernameToken>
提取用户名并将其用于登录
在ASP.NET环境中,此身份验证与用户使用用户名和密码本地登录到应用程序具有相同的效果。 为用户会话建立了一个会话cookie,经过身份验证的用户可以继续使用该应用程序。
本文不会介绍如何使用TFIM管理控制台来配置所需的信任链。 这是标准的产品行为,是本文的前提条件。
使用Tivoli Federated Identity Manager验证LTPA令牌
为了向ASP.NET应用程序进行身份验证,我们需要将LTPA cookie转换为识别用户的数据。 LTPA cookie包含加密的信息,其中一部分是经过身份验证的用户名,因此,我们需要解密cookie以提取此信息。 为此,我们使用TFIM,其中交换是WS-Trust令牌交换操作的一部分。
使用WS-Trust验证令牌涉及在<RequestSecurityToken>
消息中将令牌以及标识信息发送到TFIM信任服务。 LTPA数据作为<BinarySecurityToken>
包含在内。 信任服务配置有解密LTPA数据所需的信息,并在<RequestSecurityTokenResponse>
发出<UsernameToken>
<RequestSecurityTokenResponse>
。
可以从TFIM信任服务发布任何令牌类型,而不仅仅是我们在本文中关注的<UsernameToken>
。 例如,可以将信任服务配置为发布SAML令牌。 诸如SAML之类的令牌允许包含用户属性信息以及身份验证数据,并且TFIM信任链允许从外部数据源检索这些属性。 通过使用TFIM将LTPA令牌交换为“本地身份验证令牌”,用户身份和属性映射可以在应用程序外部进行,并且可以在多个应用程序之间共享。
本文利用了基于WSE 3.0的信任客户端,该客户端是专门为与TFIM互操作而编写的。 该信任客户端建立与TFIM信任服务的连接,并处理WS-Trust令牌验证和交换的所有方面。 在正常运行时操作期间,此信任客户端的用户将调用SendToken
,后者将SecurityToken作为参数并返回安全令牌。 TFIM信任客户端还提供了.NET BinarySecurityToken类的实现,可用于创建包含LTPA数据的SecurityToken。
下面是RequestSecurityToken和RequestSecurityTokenResponse的示例,并突出显示了相关的安全令牌。
清单1. WS-Trust消息请求
<wst:RequestSecurityToken xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust">
<wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Validate</wst:RequestType>
<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<wsa:EndpointReference xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
<wsa:Address>
http://appliesto/ut
</wsa:Address>
</wsa:EndpointReference>
</wsp:AppliesTo>
<wst:Lifetime>
<wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/ \
oasis-200401-wss-wssecurity-utility-1.0.xsd">
2007-05-25T10:16:32Z
</wsu:Expires>
</wst:Lifetime>
<wst:Issuer>
<wsa:Address xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
http://issuer/ltpa
</wsa:Address>
</wst:Issuer>
<wst:Base>
****** REQUEST SECURITY TOKEN ******
<wsse:BinarySecurityToken
ValueType="wsst:LTPAv2"
EncodingType="http://docs.oasis-open.org/wss/2004/01/ \
oasis-200401-wss-soap-message-security-1.0#Base64Binary"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/ \
oasis-200401-wss-wssecurity-utility-1.0.xsd"
wsu:Id="SecurityToken-de6c4e13-1e5d-493e-99ab-11cd29786990"
xmlns:wsst="http://www.ibm.com/websphere/appserver/tokentype"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/ \
oasis-200401-wss-wssecurity-secext-1.0.xsd">
PjlTMdkTM+wmXVEgWftVSxFwgI9VMJrX7E5NLb7uZ8eIJjJu8UbjUSyLjQkmy8Ty4ADxphL0uwpMixmV0g9z6H4M
/QljibP7G6HoGwGHzwhBb9kSw2haAu1jqDR464kNw6k6ltyMqa2TPTlRv3dSQtYLKA2icuOpVZbdtJ3
YStO8hmV/jSW9Srn9a/Shmtvsy2ioY9XLRHUeTrbTiC5vS7Tr7jVtt7cQ8bByYQWIpAicbUNbl7Szs8
KzGu3YLQeIIELBjMzAy8set2SMqvsGON2a+67vBOrK/fJWxhHwdvVNo/SHkGDxwLUMnbJFBuwI1sB9F
C2zdTCdV1m2qkNLSDrnoq16xR9DUMacwZfpQe5T/BQaI7T8fk6dGtLDtaLyScxIgDes09zqlsJ07Hk/
z25GSluI0c+xG4UiV8RBcYISsDim3ctmXl5mrFWYANTx9swxt9xecJg8XxzsI6GYtB+rl1cSWi69gqr
/bw7gohmOSMfgNSCH/TNYrgywbZr2ELolq9aRH4bqWF6Z9H7gNn3k8HFre7NGgHiK+pUSoJ6NKSEdqI
Dj+gH0EYe4iDKMZ/yInnp7CcA/YNDgYCO+gk9HeUG7E3kvVzkTEeeQ9pZap6TMTO/WICA6DWPo9ni0D
5fsQAt9cupjO0FNG9LDMw==
</wsse:BinarySecurityToken>
****** END TOKEN ******
</wst:Base>
</wst:RequestSecurityToken>
清单2. WS-Trust消息响应
<wst:RequestSecurityTokenResponse
wsu:Id="uuidc1e33769-0112-1735-97e4-d4048103371d"
xmlns:wst="http://schemas.xmlsoap.org/ws/2005/02/trust"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/ \
oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wst:RequestedSecurityToken>
****** RESPONSE SECURITY TOKEN ******
<wss:UsernameToken
wsu:Id="usernamec1e33768-0112-1622-94c7-d4048103371d"
xmlns:wss="http://docs.oasis-open.org/wss/2004/01/ \
oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/ \
oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wss:Username>cn=wasadmin,o=ibm,c=au</wss:Username>
<wss:Nonce
EncodingType="http://docs.oasis-open.org/wss/2004/01/ \
oasis-200401-wss-soap-message-security-1.0#Base64Binary">
EYwGA+FKLJycIkprkdJr8A==
</wss:Nonce>
<wsu:Created>2007-05-25T06:18:52Z</wsu:Created>
</wss:UsernameToken>
****** END TOKEN ******
</wst:RequestedSecurityToken>
<wst:RequestedAttachedReference xmlns:wss="http://docs.oasis-open.org/wss/2004/01/ \
oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wss:SecurityTokenReference>
<wss:Reference
URI="#usernamec1e33768-0112-1622-94c7-d4048103371d"
ValueType="http://docs.oasis-open.org/wss/2004/01/ \
oasis-200401-wss-username-token-profile-1.0#UsernameToken"
xmlns:wss="http://docs.oasis-open.org/wss/2004/01/ \
oasis-200401-wss-wssecurity-secext-1.0.xsd" />
</wss:SecurityTokenReference>
</wst:RequestedAttachedReference>
<wst:Status>
<wst:Code>http://schemas.xmlsoap.org/ws/2005/02/trust/status/valid</wst:Code>
</wst:Status>
</wst:RequestSecurityTokenResponse>
请与作者联系以获取有关TFIM 6.1.1的LTPA令牌模块的可用性的更多信息。
在返回的<wss:UsernameToken>
中,以完全合格DN的形式返回Username参数,该名称与LTPA数据中指定的完全相同。 在.NET环境中,应用程序通常期望使用不合格的用户ID,这是违反直觉的。 为了解决此问题,我们在TFIM映射中包含了一个自定义XSL,可从完全合格的DN中提取用户ID。
清单3. XSL映射模块
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
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:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<!-- 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="http://docs.oasis-open.org/wss/2004/01/ \
oasis-200401-wss-wssecurity-secext-1.0.xsd">
<stsuuser:Value>
<xsl:value-of select="substring-before(substring-after($username,'uid='),',')"/>
</stsuuser:Value>
</stsuuser:Attribute>
</xsl:template>
</xsl:stylesheet>
使用此映射样式表后,返回的UsernameToken不再包含完全限定的用户名。
样例应用
本文借鉴了有关Tivoli Federated Identity Manager和.NET集成的另一篇developerWorks文章的示例应用程序: http : //www-128.ibm.com/developerworks/tivoli/library/t-tfimbg-asp/ 。
该示例应用程序是一个简单的Web应用程序,它显示有关当前用户会话的信息。 标准ASP.NET身份验证API用于对用户进行身份验证,并且最初使用基于表单的登录来实现身份验证。
LTPA身份验证HTTP模块
现在我们有了测试应用程序,我们需要对其进行修改以接受由IBM WebSphere Application Server设置的LTPA cookie。 如上所述,我们使用WS-Trust协议与TFIM通信,并将加密的LTPA字符串(包含在域cookie中)交换为用户名。 然后,我们可以在ASP.NET中为此用户创建一个会话。 清单4显示了我们想要做的用于验证用户身份的伪代码表示。
清单4.认证模块伪代码
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
作为ASP.NET体系结构的一部分,HTTP模块允许在ASP.NET处理周期(事件)的各个点调用第三方模块。 HTTP模块可以注册以在AuthenticateRequest事件中调用。 当ASP.NET环境试图对发出请求的用户进行身份验证时,将调用为该事件注册的HTTP模块。 对于熟悉WebSphere®开发的那些读者,此模型与WebSphere Trust Association Interceptor的概念非常相似。 我们将开发一个名为“ FIMLTPAAuthenticationModule”的HTTP模块,该模块将LTPA cookie交换为UsernameToken,并使用它来将用户认证为ASP.NET。
清单5显示了完成的IHttpModule实现的代码。
清单5.认证模块的实现
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 =
"http://www.ibm.com/websphere/appserver/tokentype/5.0.1";
private static string LTPA_V2_NAMESPACE =
"http://www.ibm.com/websphere/appserver/tokentype";
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(
CONFIG_FIM_SERVER);
string issuer = System.Configuration.ConfigurationManager.AppSettings.Get(
CONFIG_FIM_ISSUER);
string appliesTo = System.Configuration.ConfigurationManager.AppSettings.Get(
CONFIG_FIM_APPLIES_TO);
trustClient = FIMTrustClientFactory.createTrustClient(
new Uri(uri), issuer, appliesTo);
}
#region IHttpModule Members
public void Dispose() { }
public void Init(HttpApplication context)
{
context.AuthenticateRequest += new EventHandler(
this.Application_OnAuthenticateRequest);
}
public string ModuleName
{
get
{
return MODULE_NAME;
}
}
#endregion
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,
WSSecurity.EncodingTypes.Base64Encoding,ltpaCookie.Value);
requestToken.setAttribute( NAMESPACE_ATTRIBUTE, LTPA_V2_NAMESPACE);
}
else
{
ltpaCookie = ctx.Request.Cookies.Get(LTPA_V1_COOKIE_NAME);
if (ltpaCookie != null)
{
requestToken = new SimpleBinarySecurityToken(LTPA_V1_TOKEN_VALUE,
WSSecurity.EncodingTypes.Base64Encoding, ltpaCookie.Value);
requestToken.setAttribute(NAMESPACE_ATTRIBUTE,LTPA_V1_NAMESPACE);
}
}
//If we have an LTPA token, then swap it for a usable token
// using the TFIM STS
if (ltpaCookie != null)
{
//Call TFIM
try
{
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,
serializedToken);
string encryptedTicket =
FormsAuthentication.Encrypt(ticket);
//Set the Forms authentication cookie
HttpCookie authCookie = new HttpCookie(
FormsAuthentication.FormsCookieName, encryptedTicket);
ctx.Response.Cookies.Add(authCookie);
//Redirect
ctx.Response.Redirect(
FormsAuthentication.GetRedirectUrl(username, false));
}
}
}
catch (FIMTrustClientException exception)
{
//Log an error, don't proceed with login
app.Context.Trace.Warn("FIMLTPAAuthenticationModule",
"An exception occurred while exchanging token. Details: "
+ exception.Message);
}
}
}
}
}
}
请注意,作为设置身份验证Cookie的一部分,我们将接收到的SecurityToken序列化并将其放入身份验证票证中。 这允许应用程序在用户登录时访问令牌。虽然在接收到的令牌是UsernameToken的情况下用途有限,但是当返回包含更多信息(例如SAML断言)的令牌时,可以使用相同的方法。从信任服务获得并用于向ASP.NET进行身份验证。
以下屏幕快照显示了用户通过LTPA cookie登录后的测试应用程序。 “ UserData”部分包含收到的SecurityToken。
图2.应用程序登录后
将LTPA身份验证HTTP模块集成到ASP.NET应用程序中
下一步是将LTPA HTTP模块集成到示例应用程序中。 我们建议启用此步骤的三个步骤:
- 修改应用程序的
Web.config
文件以使用LTPA身份验证HTTP模块。 - 配置TFIM信任客户端的详细信息
- 绕过默认的.NET用户名身份验证
添加HttpModule
ASP.NET应用程序中HTTP模块的使用由httpModules
配置控制。 可以在计算机,站点或应用程序级别定义此配置部分。 在较高级别定义的httpModules
配置将由较低级别继承。
在我们的示例中,我们仅为联合单点登录启用了示例应用程序(未在环境中托管其他应用程序)。 我们仅在应用程序的Web.Config
的httpModules
配置部分中添加LTPA身份验证模块。 清单6显示了httpModules
配置部分及其在Web.Config
文件中的位置。
配置TFIM信任服务
为了使用TFIM信任客户端,HTTP模块需要以下参数:
表1.传递给TFIM Trust Client所需的配置参数
配置参数 | 描述 |
---|---|
fimStsUrl | TFIM信任服务的完整URL,例如http://fim.example.com:9080/TrustServer/SecurityTokenService |
发行人 | TFIM信任客户端将用于传出的<RequestSecurityToken> 消息的<Issuer> 值。 |
fimAppliesTo | TFIM信任客户端将用于传出的<RequestSecurityToken> 消息的<AppliesTo> 值。 |
这些值必须放在appSettings
,每个参数都作为单独的key
。
绕过用户名认证
.NET中WSE 3.0的默认配置尝试对作为RequestSecurityTokenResponse一部分的UsernameToken值中接收的用户进行身份验证。 对于我们的应用程序,此行为是不受欢迎的,原因有两个:
- 我们想信任从TFIM信任服务返回的用户名。
- 它要求密码或密码摘要出现在返回的令牌中。
为了绕过此身份验证机制,我们提供了名为TrustedUsernameTokenManager
的UsernameTokenManager
的实现。 根据清单6在Web.config
配置此类。
整体Web.Config
下面显示了Web.config文件的总体布局,上面概述了每个部分。
清单6.应用程序Web.config文件
<?xml version="1.0"?>
<configuration>
...
<microsoft.web.services3>
<security>
<securityTokenManager>
<add namespace="http://docs.oasis-open.org/wss/2004/01/ \
oasis-200401-wss-wssecurity-secext-1.0.xsd"
localName="UsernameToken"
type="IBM.Tivoli.FIM.TrustClient.Tokens.TrustedUsernameTokenManager, \
FIMTrustClient" />
</securityTokenManager>
</security>
</microsoft.web.services3>
...
<appSettings>
<add key="fimStsUrl"
value="http://[host]:[port]/TrustServer/SecurityTokenService" />
<add key="fimAppliesTo" value="[AppliesTo]" />
<add key="fimIssuer" value="[Issuer]" />
</appSettings>
...
<httpModules>
<add type="IBM.Tivoli.SOA.Web.FIMLTPAAuthenticationModule, \
FIMLTPAAuthenticationModule"
name="LTPAAuthModule"/>
</httpModules>
...
</system.web>
<configuration>
将HTTP模块添加到应用程序配置中的语法为<add type="[Class],[Assembly]" name="[ModuleName]" />
。 在清单5中,我们指定了名为FIMLTPAAuthenticationModule
的类,并且该类是在IBM.Tivoli.SOA.Web
命名空间中定义的,因此,我们指定的[Class]
是IBM.Tivoli.SOA.Web.FIMLTPAAuthenticationModule
。 [Assembly]
是在其中定义我们的类的CLR程序集的名称。这是在[Class]
中发现的动态链接库(DLL)文件的名称。在示例项目中,我们已经编译了FIMLTPAAuthenticationModule
模块插入FIMLTPAAuthenticationModule.dll
文件,因此这是[Assembly]
使用的值。 当定义为应用程序配置的一部分时,ASP.NET环境将尝试在全局程序集缓存或应用程序的bin子目录中定位该程序集。 我们的示例在应用程序的bin子目录中使用FIM LTPA身份验证模块。
翻译自: https://www.ibm.com/developerworks/tivoli/library/t-ltpatfim/index.html
使用ltpa时认证失败