IBM Cognos 最佳实践: 在 IBM Cognos 8 Custom Java Authentication Provider 中添加单点登录

文档性质:技术;产品:IBM Cognos 8;关注领域:安全性;版本:1.0

本文档通过解释所需的概念描述如何在 Custom Java Authentication Provider 中实现 SSO。本文档补充 SDK 文档的内容。

Cognos Proven Practices Team, Cognos 最佳实践团队, IBM

Cognos 最佳实践团队。



2011 年 6 月 02 日

免费下载:IBM® Cognos® Express V9.5 或者 Cognos® 8 Business Intelligence Developer Edition V8.4 试用版
下载更多的 IBM 软件试用版,并加入 IBM 软件下载与技术交流群组,参与在线交流。

简介

目的

标准 IBM Cognos 8 SDK 文档中的 Custom Java Authentication Provider Developer Guide 解释了编写 Custom Java Authentication Provider (CJAP) 所需的主要概念。甚至描述了身份验证可以基于什么以及如何向入口点 请求更多的信息。但是,其内容过分简短,而且没有利用这些技术在 Custom Java Authentication Provider 中添加单点登录 (SSO) 支持的实际示例。而这是向客户交付全面解决方案所必需的。

在本文档中,提供身份验证过程的背景知识并描述如何使用提供的 SDK 处理 SSO。我们将在 SDK 示例 "JDBCSample" CJAP 中添加 SSO 支持。

适用性

本文档中描述的概念和背景知识适用于 IBM Cognos 8 的所有版本。

本文档中的代码示例是用 IBM Cognos 8.4.1 开发并测试的。尽管作者无法保证代码示例可以不加调整地在产品的其他版本中正常运行,但是除了用适当的 JRE 版本重新编译(调整后的)JDBCSample 源代码之外,作者不知道有其他任何前提条件。

例外与除外责任

本文档不讨论设计和编写 Custom Java Authentication Provider (CJAP) 的一般性知识。这里只讨论在完整的身份验证提供者中添加单点登录 (SSO) 支持。

使用示例代码 (JDBCSample) 要求安装 IBM Cognos 8 SDK 并获得许可证。

本文档假设读者熟悉 CJAP SDK 和 Java 编程。


IBM Cognos 8 中的身份验证

本章全面描述 IBM Cognos 8 中的身份验证过程涉及的概念和组件。

请求和会话

用户(浏览器)或代码(SDK 应用程序)通过 Cognos 入口点 (EP) 建立 HTTP 会话,从而向 IBM Cognos 8 发送请求。有效的入口点可以是直接访问的 IBM Cognos 8 Dispatcher,也可以是部署在 web 服务器上的 IBM Cognos 8 Gateway(这是最佳实践)。

因为 IBM Cognos 8 基于面向服务架构 (SOA),所以 Cognos 系统提供的所有功能是由一套独立的服务实现的,这些服务使用 SOAP 协议与外部通信和相互通信。由于这个原因,发送给 IBM Cognos 8 入口点的每个请求必须被路由到某个能够处理它的目标服务。组成 IBM Cognos 8 的每个服务处理不同类型的请求,而路由是 IBM Cognos 8 架构的主要概念之一。

路由由 IBM Cognos 8 Dispatcher Service 处理。无论请求是直接发送给 Dispatcher 还是通过 Gateway 转发(每个 Gateway 把请求转发给其配置中指定的单一 Dispatcher),都由访问的 Dispatcher 上的 Dispatcher Service 实例处理请求。如果请求是当前 HTTP 会话中收到的第一个请求,Dispatcher Service 会创建一个新的 sessionID。接下来,给请求分配一个 requestID 并把 sessionIDrequestID 都添加到请求中。这样就可以识别同一 HTTP 会话中的所有后续请求,因为它们具有相同的 sessionID

因为服务在逻辑上是相互独立的,所以为了防止不当访问,所有服务实际上都需要先执行身份验证,然后再处理请求。在这个上下文中,身份验证意味着对请求所属的会话进行验证,由此确认请求来自经过身份验证的发送者。

IBM Cognos 8 身份验证功能由 Content Manager (CM) Service 集中地提供。因此,所有其他 IBM Cognos 8 服务都使用 CM Service 检验会话的身份验证信息或触发对未经身份验证的会话的身份验证。

Dispatcher Service 的实例处理一个请求之后,这个服务首先检查给定的会话的身份验证状态。如果会话还未经身份验证,Dispatcher Service 会使用 CM Service 运行身份验证过程并把请求传递给它。CM Service 会把请求传递给 Cognos Access Manager (CAM) 组件,这个 CM 子组件处理身份验证、授权和管理 (AAA) 以及加密 (CRP)。然后,CAM 的 AAA 子组件使用为 IBM Cognos 8 配置的身份验证提供者 访问身份验证源,从中读取用户的相关信息,最终对请求和会话执行身份验证。

图 1 身份验证的示意图
图 1 身份验证的示意图

如果身份验证成功,就把身份验证信息存储在 Content Store 中并在会话中添加引用,后续的请求并不传递给 CAM,因为所有服务现在可以直接从会话获得身份验证信息的引用并让 CM Service 检验它。

经过可配置的空闲时间之后,会话将超时,Dispatcher Service 会再次请求 CAM 对会话执行身份验证。

身份验证提供者

IBM Cognos 8 身份验证提供者是用 Java 或 C++ 实现的软件模块,它与 Cognos Access Manager (CAM) 组件交互。正如 Custom Authentication Provider Developer Guide 指出的,有两类身份验证提供者。

完整的身份验证提供者实现了根据某一身份验证源检验提供的凭证的功能(身份验证源存储并管理用户、组和/或角色类型的条目)。另外,它支持搜索条目并能适应身份验证源的层次结构。身份验证提供者必须支持至少一种身份验证方法,很可能支持多种方法,还可以支持单点登录。

但是,可信登录提供者 (TSP) 只提供用于单一用途的非常有限的功能。在单点登录场景中,它读取会话中可能存在的令牌,令牌是由识别用户的更高的身份验证层放在会话中的。假设任何其他 IBM Cognos 8 身份验证提供者都无法直接使用这种令牌。TSP 把令牌中的信息转换为完整身份验证提供者可以使用的信息,并把身份验证过程交给某一个完整身份验证提供者。它本身并不验证用户的身份,仅仅转发并转换信息,因此不会导致在 Cognos Connection 的 Directory 工具中出现名称空间条目。

下表描述 IBM Cognos 8 提供的开箱即用身份验证提供者。但是,并非每个提供者都可用于每种平台。在 Linux 和 HP-UX Itanium 上,只能使用 LDAP 提供者。

除了这些开箱即用的提供者之外,客户还可以使用 IBM Cognos 8 SDK 中的 Custom Authentication Provider SDK 实现自己的身份验证提供者(只适用于 Java)。基于这个 SDK 编写的身份验证提供者称为 Custom Java Authentication Provider (CJAP),其类型可以是完整TSP。实际上,产品已经包含一个用于为门户服务器实现单点登录的 CJAP —— Shared Secret 提供者。

 WindowsUNIXLinux, HP-UX Itanium
Active Directory可用不可用不可用
NTLM可用不可用不可用
SAP可用可用不可用
Series 7可用可用不可用
LDAP可用可用可用
CA Siteminder (TSP)可用可用不可用
Shared Secret (CJAP,TSP)可用可用可用

除了 CJAP(CJAP 使用专有的配置方法),所有提供者都通过在 Cognos Configuration 中创建的名称空间配置 (资源)进行配置。可以在这里配置提供者特有的属性。当启动 IBM Cognos 8 Content Manager 时,在配置中扫描名称空间配置 并根据配置的设置初始化相应的提供者。

从 IBM Cognos 8 开始,所有开箱即用提供者都支持 Test 功能,通过在 Cognos Configuration 的管理器树中右键单击名称空间配置元素使用此功能。此功能用配置的设置对提供者进行一定程度的初始化。但是,这种测试无法检验提供者支持的所有功能,它只用于发现明显的配置错误和连接问题。

一般的身份验证过程

当 CAM 收到要执行身份验证的请求时,首先根据配置决定身份验证类型。如果系统配置为允许匿名用户,那么会话成为使用特殊匿名用户的已验证会话,因为在 IBM Cognos 8 中没有真正的匿名会话。使用一个内部身份验证提供者实现此功能,它是不可见的,也不可配置。它使用某种硬编码的伪用户凭证(不包含用户名或密码),因此不需要登录。

对于非匿名访问,CAM 使用配置的身份验证提供者检验请求,因此会把请求传递给配置的提供者之一。根据可用性(即在已经正确地初始化的提供者之中选择)和包含要使用的名称空间 namespaceID 的参数决定使用哪个提供者。

尽管很可能期望单一请求包含所有登录数据(身份验证所需的信息),比如要检验的名称空间和凭证,但是事实并非总是如此。

对于登录数据不全的请求,向发送者返回一个符合规范的响应,它让发送者发送另一个包含更多信息的请求。身份验证提供者可以以这种方式向发送者(用户或 SDK 程序)或转发请求的入口点(Gateway 或 Dispatcher)请求更多信息。这些回调的典型应用方式是提示用户输入自己的凭证、让用户在几个配置的身份验证提供者中选择一个或者让入口点从它的环境获取某些可信的变量值(这是 SSO 的典型做法)。

独立地处理发送给 CAM 的每个请求,但是给定的会话的登录过程可能由一系列请求组成。Custom Authentication Provider Developer Guide 的第 2 章 Authentication Requests: flow scenarios 中描述了三个这样的场景。

只有在单一请求包含所有必需的登录数据的情况下,提供者才会真正开始尝试验证请求。在讨论下一个身份验证步骤之前,我们先看看提供者可以或需要接收的登录数据的类型。

登录数据

把请求中的登录数据传递给身份验证提供者有四种方法。

  • 可信的凭证 (TC)
    这种凭证是由某个身份验证提供者在以前为一个 IBM Cognos 8 用户创建的并(加密)存储在 Content Store 中。例如,时间表可能与 TC 的引用(凭证路径)一起存储。从技术上说,这种凭证可以是二进制令牌或用户和密码等字符串。但是,在请求中只传递凭证路径,TC 不会离开 Content Store。
    当收到 TC 时,身份验证提供者并不显式地检验其来源或一致性,只隐式地检验。函数 getTrustedCredentialValue() 从 Content Store 获取实际的凭证值并解密,从而检验完整性和来源。提供者只需根据身份验证源运行身份验证。但是,TC 可能会过时,例如在 Content Manager 中存储密码之后在身份验证源中更改了密码。在这种情况下,TC 所属的用户必须亲自通过 Cognos Connection 重建它们。
  • 凭证
    凭证也称为 SDK 凭证,当 SDK 程序向 IBM Cognos 8 进行身份验证时发送这种凭证。从技术上说,它们是用户和密码等字符串(密码不是必需的)。除非使用 SSL,否则在请求中以明文传递凭证。
    身份验证提供者根据身份验证源检验它们。
  • 表单字段 —— 用户名和密码
    如果运行 Basic Authentication,就意味着提示用户输入用户名和密码,HTML 代码会提交在两个预定义的表单字段中输入的凭证。它们在发送给入口点的请求中是可见的,但是在 Gateway 解析请求之后,在传递给 CAM 的请求中会隐藏密码。如果入口点是 Dispatcher,则不支持此功能。
  • (可信的)环境变量、cookie 或一般性 SSO 令牌
    身份验证提供者可能允许从环境变量或某个二进制令牌 读取用户身份信息。
    并不从请求中直接读取这些变量或令牌的值,而是由入口点组件通过前面提到的回调提供它们。因此,支持这些回调也需要入口点层组件中的代码。
    当前支持的二进制 SSO 令牌(只在 Windows Gateway 上)只有 Microsoft Windows Kerberos 令牌。但是,处理环境变量的代码(在任何 Gateway 和 Dispatcher 平台上都支持)接受一般性变量,包括可信的变量(比如 REMOTE_USER、USER_PRINCIPAL)和任意变量(HTTP_REFERRER、HTTP_xxxx)。

产品提供的所有完整身份验证提供者都支持这四种方法。Custom Java Authentication Provider 可以选择只支持其中一部分,或者支持其他方法。

在会话中保存身份验证信息

在处理请求时,身份验证提供者会访问它的身份验证源,从中读取信息以检验传递的身份信息。如果身份验证成功,提供者会为用户/客户机身份验证所针对的名称空间颁发一个 visa。

visa 维护用户的安全上下文,即登录数据(用来向 IBM Cognos 8 验证身份的数据)和用户的身份(用户所属的组和角色)。使用 visa 提供凭证(由以前的身份验证过程保存的要传递给其他服务的登录数据),当另一个 IBM Cognos 8 服务请求身份验证、调度报告或向数据源验证身份时使用 visa 提供的凭证。visa 被添加到一个内存内 CAM 表中,这个表包含所有活跃的 visa。每个成功完成身份验证的名称空间有一个 visa,一个会话(也就是一个用户/客户机)的所有 visa 组成一个 Passport。它们在这个表中共享相同的主键 Passport ID。只向 CAM 公开这个 Passport ID 作为引用。返回给 CM 和用户/客户机的是 Passport ID。

对于浏览器客户机,Passport ID 存储在浏览器内存中的会话 cookie 中;对于 SDK 程序,由应用程序负责在会话期间管理 Passport ID

请求更多信息(身份验证舞蹈)

如果请求没有包含完成身份验证事务所需的足够信息,身份验证提供者会使用前面提到的回调功能。这个特性让身份验证提供者能够向用户或系统请求更多信息。

请求信息的方法称为 “异常”,因为它使用与 Java 异常相似的概念。调用者(即请求的发送者)负责处理异常。

IBM Cognos 8 身份验证提供者可以返回三种异常:

  • UserRecoverable Exception (camAuthUserRecoverable, error -36)
    向发送者指出,最终用户/客户机需要提供(更多)数据,应该把这些数据包含在新请求中。例如,这可能意味着用户需要选择要身份验证的名称空间或输入凭证。
  • SystemRecoverable Exception (camAuthSystemRecoverable, error -37)
    向入口点指出,系统必须获得更多数据,但是不需要进一步的用户/客户机交互。额外信息必须包含在发送给 CAM 的新请求中。例如,这可能意味着在 Gateway 上获取系统/环境变量的值。
  • Unrecoverable Exception (camAuthUnRecoverable, error -38)
    表示无法通过任何措施纠正的错误。这通常表示提供者内部出现了某种问题,不可能执行身份验证,在这个身份验证事务中不必发送新请求。

每个异常都携带其特有的额外信息,这些信息向发送者指出拒绝处理请求的原因或接下来可以采取的措施。

发送者负责以适当的方式处理这些异常,比如重新发送包含更多信息的请求,或者通过其他服务(比如表示服务)驱动操作。这意味着,在最终完成请求的身份验证或最终失败之前,在身份验证提供者与入口点/客户机/用户之间可能会有多轮交互。

CAM 与调用者之间的往返交互称为 “身份验证舞蹈 ”;调用者可以是入口点(Gateway 或 Dispatcher)或者 SDS 等其他组件(SDS 调度身份验证凭证的提交以实现 “run-as”)。

对于需要用户提供更多信息的情况 (UserRecoverable Exception),系统会生成 HTML 页面并把它返回给客户机/用户的浏览器。生成的页面包含 HTML 表单以提示用户哪些信息是必需的,并把信息提交给 Cognos;或者对于 SDK 客户机,指出客户机必须传递的额外变量。

对于需要系统(环境)提供更多信息的情况,过程有点儿复杂。

SystemRecoverable Exception 包含一个加密的数据字段,其中包含身份验证提供者请求的环境变量的名称。尽管原来的请求可能已经包含变量(比如 REMOTE_USER),但是提供者不会接受原请求中的值,因为它们太容易被篡改或注入,提供者不相信这些值。为了从可信的源(比如入口点)获取值,它向入口点请求变量。发送者(在这里是入口点)从它的本地环境读取变量并在发送给提供者的响应中提供值(如果值不可用或没有找到,就提供 NULL)。入口点把从环境得到的信息添加到原请求中的同一加密字段中,以修改后的请求作为响应。对于提供者来说,这只是另一个身份验证请求,但是这一次它包含更多信息,可能能够成功地处理。

单点登录与可信登录

为了实现无缝的登录体验,IBM Cognos 8 支持两个概念。

单点登录 (SSO) 意味着 IBM Cognos 8 会从前面的身份验证层(比如身份验证代理)取得某种用户 ID。Cognos 不会再次提示用户输入凭证。IBM Cognos 8 身份验证提供者会检查某个 HTTP 变量(对于某些提供者可配置)或 cookie 以获得 SSO 所需的登录数据。通过使用身份验证舞蹈获得必需的信息。

对于可信登录 (TSO),可以编写特殊类型的 IBM Cognos 8 身份验证提供者 — Trusted Signon Provider (TSP) 1。这种提供者接受某个令牌并从中推导出身份验证提供者可使用的登录数据。TSP 不是完整的提供者,它不连接 LDAP 等身份验证源,它只是让某种 SSO 令牌变得可访问的代理。在下一步中,使用标准的 REMOTE_USER 头把登录数据传递给一个完整的 IBM Cognos 8 身份验证提供者,大多数开箱即用的身份验证提供者都支持 REMOTE_USER 头。但是,与 SSO 的情况相反,完整的提供者在这种情况下不使用身份验证舞蹈,而是相信 REMOTE_USER 中传递的登录数据,因为它来自可信的源 — TSP。

与其他场景一样,对于这两种情况,IBM Cognos 8 并不亲自验证用户的身份,而是依靠第三方身份验证源执行身份验证。但是对于单点登录或可信登录,IBM Cognos 8 根本不检验用户的凭证,而只是依赖于查找并假设以前已经根据适当的凭证验证了用户的身份。对于查找,IBM Cognos 8 必须能够访问一个身份验证源,在其中根据头/cookie 中传递的信息搜索用户。但是,它不必是同一身份验证源。

例如,如果某个基于 LDAP 的身份验证代理已经验证了用户的身份,代理在 REMOTE_USER 中传递某个值,那么对于 IBM Cognos 8,可以为 Series7 配置使用 OSSignon 的身份验证提供者,由此支持根据传递的信息查找用户。但是在这种情况下,最好使用指向同一 LDAP 的 LDAP 身份验证提供者,从而确保查找到正确的用户,因为任何映射都可能出错。

1 对于 CA Siteminder 这样的开箱即用提供者,可以使用 IBM Cognos8 Authentication Provider SDK 开发其他身份验证代理。


为 Custom Java Authentication Provider 实现 SSO

前一章解释了 IBM Cognos 中的身份验证涉及的概念和组件。以这些知识为基础,我们现在可以讨论如何在 CJAP 中实现 SSO。

在本文档中,我们主要关注完整的身份验证提供者。要想支持 SSO,提供者必须实现对第四类登录数据的支持,即 2.3.1 节 — 登录数据 中提到的环境变量。除环境变量之外,提供者支持的其他登录数据类型与 SSO 无关,无论提供者是否必须允许调度可信凭证。如果用户应该能够输入凭证,那么还必须实现基于表单的方法。最后,如果应该使用 SDK 应用程序和工具(比如 trigger.sh 或 /bin/utilities 文件夹中的诊断工具),那么必须支持 SDK 凭证。

本文档以 IBM Cognos 8 SDK 中 “JDBCSample” 的代码为基础演示技术。我们将添加对所有登录数据类型的支持并实现基于 REMOTE_USER 的 SSO。

当把请求传递给提供者时,就意味着调用提供者的 authenticate() 方法。在这个方法中,提供者必须处理所有身份验证步骤:识别登录数据的类型,用身份验证源运行身份验证,最终颁发 visa 并把它添加到 passport 中。对于本文档,我们只讨论第一步(识别登录数据的类型),其他步骤因支持的身份验证源而异,因此超出了范围。详细信息参见 JDBC 示例源代码。

对于识别登录数据类型,一种已经证明有效的做法是使用嵌套的 IF 语句检查可信凭证、凭证和表单,最后检查 SSO。尽管不要求按照特定的次序,但是坚持这个次序有好处,可以保持代码简单。只有在没有提供显式的登录数据的情况下,代码才应该尝试处理 SSO。

每个登录数据类型在 IBiBusHeader2 类中有一个对应的函数,用于从传递给 logon() 函数的请求中获取登录数据。

还有 getTrustedCredentialValue(),可以用参数 user name 或 password 调用它以从可信凭证读取相应的值。对于 SDK 凭证,有相似的函数 getCredentialValue(),它的用途是相似的。使用 user name 或 password 参数调用它,就可以从 SDK 凭证获得值。

对于基于表单的身份验证,有登录页面,用户在其中使用两个表单变量 CAMUsername 和 CAMPassword 输入用户名和密码。使用这些名称作为参数调用 GetFormFieldValue(),就会从请求获得表单字段。当然也可以在 GET URL 中传递这些字段。

最后,对于读取环境变量,有两个函数:

  • getEnvVarValue()
    这个函数按原样从请求读取 HTTP 头的值。也就是说,它不触发身份验证舞蹈,仅仅获取在请求中传递的值。尽管在某些场景中这可能足够了,但是会导致很高的被欺骗的风险。在请求中注入 HTTP 头是非常容易的,因此任何人都能够在请求中添加 REMOTE_USER 头和想要的任何值。因此,不赞成使用这个函数实现 SSO。
  • GetTrustedEnvVarValue()
    可以使用这个函数触发 2.3.3 节中描述的身份验证舞蹈,从而获取在传递给它的参数中指定的变量。这假设发送给提供者的请求中的 HTTP 头包含在 web 服务器本地作为 CGI 环境变量存储的值。身份验证舞蹈让入口点从其环境读取变量值并把值发送给提供者。因为变量是从一个 Cognos 组件(入口点)获取的,传输时经过签名和加密,足够安全,所以提供者会相信它的值。

显然,我们希望使用 getTrustedEnvVarValue() 函数。正如 2.3.3 节提到的,为了触发身份验证舞蹈,必须向入口点返回一个异常。在提供者代码中必须显式地处理异常。getTrustedEnvVarValue() 函数返回 NULL 或字符串。如果返回 NULL,就表明还没有收到可信的值。这意味着提供者代码现在必须抛出一个 SystemRecoverable Exception 并请求想要的值。从提供者的角度来看,对这个请求的处理到这里就完成了。当新的请求到达并再次调用 GetTrustedEnvVarValue() 时,它会返回字符串。如果这个字符串是空的(其长度为 0),入口点就无法获取想要的变量值,这意味着还没有设置它。这意味着 SSO 失败了,提供者应该通过抛出 UserRecoverable Exception 要求输入凭证,从而返回到基于表单的身份验证,或者抛出 Unrecoverable Exception。如果字符串非空,它就包含请求的变量值。

因此,提供者本身必须抛出 SystemRecoverable Exception 并在其中提供请求的变量的名称。涉及的所有其他功能对于开发人员是透明的,比如对值进行加密、对在提供者和入口点之间传输数据所用的专有头进行签名。

下面的代码片段取自 JDBCSample 示例应用程序源代码,它是 Logon() 函数的一部分。它用三个 IF 语句依次检查三类登录数据。只有在 usernamepassword 之一非空的情况下,代码才会检验登录数据或颁发 visa。如果 usernamepassword 都没有赋值为从登录数据获取的值,代码会抛出 UserRecoverable Exception;如果客户机是浏览器,就会显示登录屏幕。

我们希望在这段代码中添加对第四类登录数据(可信的环境变量,在此示例中是 REMOTE_USER)的支持。

String[] username = null;
	String[] password = null;

	//	1 - Look for trusted credentials
	username = theAuthRequest.getTrustedCredentialValue("username");
	password = theAuthRequest.getTrustedCredentialValue("password");
	if (username == null && password == null)
	{
		// 	2 - Look for credentials coming from SDK request
		username = theAuthRequest.getCredentialValue("username");
		password = theAuthRequest.getCredentialValue("password");
	}
	if (username == null && password == null)
	{
		//	3 - Look for credentials in formfield
		username = theAuthRequest.getFormFieldValue("CAMUsername");
		password = theAuthRequest.getFormFieldValue("CAMPassword");
	}		

	if (username == null || password == null)
	{
		UserRecoverableException e = new UserRecoverableException(
				"Please type your credentials for authentication.",
				"The provided credentials are invalid.");
		e
				.addDisplayObject(new TextDisplayObject("User ID:",
						"CAMUsername"));
		e.addDisplayObject(new TextNoEchoDisplayObject("Password:",
				"CAMPassword"));
		throw e;
	}

简单的方法是在寻找来自表单字段的凭证之后添加第四个 IF 块。但是这意味着,无论这个 IF 块中发生什么,都必须填充 usernamepassword,这样无论是否在最后的 IF 语句中已经收到了数据,都能通过最后的测试。SSO 通常不提供密码,SSO 的用途是避免多次提供密码,而且以明文传递密码在安全上有风险。因此,应该假设我们的 SSO 不提供密码。这意味着必须修改最后一个 IF 语句,允许只有用户名的情况,但是这个逻辑只适用于 SSO。

这不完全正确。如果支持 SSO,那么也可以使用它生成可信的凭证。这意味着,如果用户通过 SSO 向 IBM Cognos 8 验证了身份,登录数据会只有用户名。因此,如果调用提供者已生成与时间表一起存储的 TrustedCredential,它可以只基于用户名生成这个凭证。当以后执行这个时间表时,这些只由用户名组成的 TrustedCredential 被提供给提供者。因此,一旦提供者支持 SSO,它就必须处理可能只包含用户名的(可信)凭证,也就是说基于可信凭证的身份验证也必须允许只有用户名。

可以把允许只有用户名的范围扩展为包括基于 SDK 凭证的身份验证,但是 SDK 客户机通常具有足以提供完整凭证的功能,完整凭证是用户名密码。建议保留要求完整凭证这个逻辑。

根据上面的分析,合理的方法应该是修改代码片段的部分逻辑,把 IF 语句的结构由顺序改为嵌套。这样就可以针对每个类型分别对登录数据的内容做出决策。为了通过最后一个 IF 语句,只需对于 SSO 用用户名填充密码。

下面是可能的解决方案的示例。

String[] username = null;
String[] password = null;
//	1 - Look for trusted credentials
username = theAuthRequest.getTrustedCredentialValue("username");
password = theAuthRequest.getTrustedCredentialValue("password");
// since pw can be empty we scan for either username or password
if (username != null)
{// we found some value for username in TC, now lets see about pw
	 if (password == null) password=username;
   // we simply set password= username in case we didn't get one from TC
   // possibly some log output here 
}
else
{  // 	2 - Look for credentials coming from SDK request
  username = theAuthRequest.getCredentialValue("username");
  password = theAuthRequest.getCredentialValue("password");
  if (username != null && password != null)
  {
	  // we found Sdk credential, all good
    // possibly some log output here
  }
  else
  { //	3 - Look for credentials in form field
	   username = theAuthRequest.getFormFieldValue("CAMUsername");
	   password = theAuthRequest.getFormFieldValue("CAMPassword");
    // Note: using AND here implies that the provider will check for SSO 
    //       if a user typed in username and an empty password. Though
    //       it introduces overhead, this can be neglected as it enforces
    //       correct logic on the other hand. 
	   if (username != null && password != null)
		{
		  // found credentials in form field, all good
      // possibly some log output here 
	}
	else
	{  //	4 - Look for REMOTE_USER header variable
    username = theAuthRequest.getTrustedEnvVarValue("REMOTE_USER");
		if (username == null) 
		{
	  	  // null implies the provider has to start the dance so throw a SysRecov.
		  // the SysRecov needs to have the name of the variable we look for in
		  // the second parameter
		  SystemRecoverableException e = new SystemRecoverableException(
							"Challenge for REMOTE_USER",
							"REMOTE_USER");
		  throw e;
		}
		// username is != NULL so we have to investigate if we got something back 
    // from the dance 
		if (username[0].length() == 0)
		{// this indicates the variable does not exist or is empty. Bail out by
     // erasing username and password. Final IF will cause UserRecoverable
		  username=null;
		  password=null;
		}
		else 
		{  // OK, we got something, so fake password, just to pass the 
		  // if clause further down.
		  password = username;
		}
	}
 }
}

按照这种逻辑,提供者会触发身份验证舞蹈并获取 REMOTE_USER。如果这个变量在入口点环境中有值,就会把它传输给 usernamepassword

接下来只需处理凭证并用身份验证源检验它们。请记住,如果 username=password,那么凭证是 SSO 或可信凭证。在这两种情况下,提供者都采用 Trusted Signon 的概念,因此不检验凭证,只运行查找。

可以通过这种技术使用任何 HTTP 头变量。不能使用 cookie,因为入口点不支持它们。实际上应该在 TSP 中处理 cookie,然后传递给使用基于 REMOTE_USER 的 SSO 的完整身份验证提供者。

上面的代码片段实际上不会让 JDBCSample 正常工作。示例代码依赖于把用户名和密码传递给 JDBC 驱动程序,而且只有在使用这些凭证成功地建立 DB 连接的情况下,才会颁发 visa。但是,如果创建一个以用户名作为密码的用户,示例会正常工作。本文档选用 JDBCSample 作为示例只是因为它是完整身份验证提供者的惟一示例。要点在于,根据返回码,可能要调用 GetTrustedEnvVarValue() 两次。

参考资料

学习

获得产品和技术

讨论

  • 参与 developerWorks 博客 并加入 developerWorks 中文社区,developerWorks 社区是一个面向全球 IT 专业人员,可以提供博客、书签、wiki、群组、联系、共享和协作等社区功能的专业社交网络社区。

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Information Management
ArticleID=677483
ArticleTitle=IBM Cognos 最佳实践: 在 IBM Cognos 8 Custom Java Authentication Provider 中添加单点登录
publish-date=06022011