SharePoint 安全性

修整 SharePoint 搜索结果,提高安全性

Ashley Elenjickal

下载代码示例

Microsoft SharePoint 搜索功能使用一个对整个存储库具有完全读权限的帐户对库的内容进行索引。因此,当用户查询某些内容时,应当只能看到授权给该用户的文档,这一点非常重要。SharePoint 使用与每个文档关联的访问控制列表 (ACL) 来修整查询结果,以剔除用户没有查看权限的文档,但是 SharePoint 提供的默认修整功能(现成修整功能)并不总是能满足数据的安全性需要。在这种情况下,您可能需要根据组织的身份验证结构进一步修整查询结果。

这就是 SharePoint 自定义安全修整基础结构有用的地方。SharePoint 使您能够在单独的模块中实现业务逻辑,然后将其集成到查询处理器(用于提供查询服务)的工作流当中。在安全修整功能路径中,自定义查询修整功能紧跟在现成安全修整功能之后。这样,执行自定义修整功能之后,查询结果的数量必然会等于或少于注册自定义安全修整器 (CST) 程序集之前的文档查询结果。

在深入了解 CST 体系结构之前,请先快速了解 SharePoint 搜索以及新的声明身份验证基础结构。

SharePoint 搜索概述

从较高层次来看,搜索系统可以分为两个独立的部分:收集器管道和查询处理器管道。

收集器管道 这个部分负责对来自各个存储库(例如 SharePoint 站点、HTTP 站点、文件共享、Lotus Notes、Exchange Server 等等)的内容进行爬网和索引。这个组件位于 MSSearch.exe 中。当发出一个存储库爬网请求后,收集器会调用筛选器后台程序 (MssDmn.exe) 来加载在连接、提取和解析内容时所需的协议处理程序和筛选器。图 1 展示了一个简化的收集器管道视图。

图 1 简化的 SharePoint 收集器管道视图

SharePoint 只能使用 Windows NTLM 身份验证帐户进行爬网。您的内容源必须向爬网请求中附带发送的 Windows 帐户授予权限,才能访问文档内容。尽管 SharePoint 2010 支持声明身份验证,收集器仍然不是支持声明的应用程序,因此不会访问仅具备声明身份验证的内容源。

查询处理器管道 在 SharePoint 2010 中,查询处理器管道中两个最重要的更改出现在拓扑可伸缩性和身份验证模式方面。在 Microsoft SharePoint Server (MOSS) 2007 中,查询处理器(搜索查询和站点设置服务,从此处开始称为搜索查询服务)与 Web 前端 (WFE) 运行在同一个进程中,但是在 SharePoint 2010 中,它可以在场中的任何位置运行,并且还可以作为 Web 服务运行。

WFE 通过 Windows Communication Foundation (WCF) 调用与搜索查询服务通信。搜索查询服务现在完全构建在 SharePoint 声明身份验证基础结构之上。这会将 SharePoint 搜索功能从与 Windows 身份验证和窗体身份验证的紧密结合中解脱出来。因此,SharePoint 现在支持各种身份验证模式。搜索查询服务按照发出查询的用户的权限对搜索结果进行修整。当现成修整操作完成后,搜索查询服务会调用自定义安全修整器。请参见图 2,以了解执行查询时涉及到的各个组件。

图 2 源自 SharePoint 站点的搜索中心的查询工作流

自定义安全修整功能是查询管道的一部分,因此我们的讨论将限制在查询管道的组件中。

SharePoint 2010 中的声明身份验证

若要在 CST 程序集中实现自定义修整逻辑,必须对 SharePoint 2010 中的声明身份验证支持有一个基本了解。在声明身份验证环境中,用户标识在一个称为安全令牌的信封中进行维护。它包含一系列关于用户的标识断言或声明。声明的示例包括用户名、电子邮件地址、电话号码、角色等等。每个声明都会有多种特性,例如类型。例如,在一个声明中,UserLogonName 可能是类型,而当前登录的用户的名称可能是

安全令牌是由一个称为安全令牌服务 (STS) 的实体颁发的。这是一个用来响应用户身份验证请求的 Web 服务。对用户进行身份验证后,STS 返回一个包含用户所有权限的安全令牌。可以将 STS 配置为位于同一个 SharePoint 场中,也可以将其配置为场外的另一个 STS 的依赖方:这两种配置方式分别称为标识提供程序 STS (IP-STS) 和依赖方 STS (RP-STS)。在设计 SharePoint 部署时,您必须仔细考虑是要使用 IP-STS,还是 RP-STS。

在简单安装中,SharePoint 使用产品附带的默认声明提供程序。即使您完全使用 Windows 身份验证设置场,在发出一个查询时,搜索服务应用程序代理还是会与 STS 通信,将所有用户声明提取到安全令牌中。此令牌随即通过 WCF 调用传递到搜索查询服务。

自定义安全修整操作的工作流

图 3 所示,可以用一个简单的流程图演示 CST 的工作流逻辑。

图 3 CST 的工作流逻辑

如前所述,搜索查询服务首先执行现成安全修整操作,然后查找是否存在任何与搜索结果相关联的 CST。特定内容源与某个 CST 的关联操作是通过为该内容源定义一个爬网规则 实现的。如果搜索查询服务发现了与搜索结果中的任何 URL 相关联的 CST,它就会调用该修整器。修整器会加载到与搜索查询服务相同的 IIS 工作进程 (w3wp.exe) 中。

一旦加载修整器,搜索查询服务就会通过一个与您先前定义的爬网规则相关联的现成修整 结果集,调用修整器内部实现的 CheckAccess 方法。CheckAccess 方法决定某个特定的 URL 是否应当包含在返回给用户的最终结果中。这通过返回一个位数组来完成。将此数组内的位设置为 true 或 false,将会“包含”或“阻止”URL 显示在最终结果集中。如果您由于性能或其他意外原因想要停止处理 URL,则必须引发 PluggableAccessCheckException。如果您在处理完一部分 URL 后引发该异常,处理结果还是会返回给用户。搜索查询服务将会从最终结果集中删除所有未处理过的 URL。

部署自定义安全修整器的步骤

简而言之,成功部署一个 CST 需要五个步骤:

  1. 实现 ISecurityTrimmer2 接口。
    1. 使用托管代码实现 Initialize 和 CheckAccess 方法
    2. 创建一个程序集签名文件,并将其包含到项目中
    3. 生成程序集
  2. 将修整器部署到运行搜索查询服务的所有计算机的全局程序集缓存 (GAC) 中。
  3. 为您想要进行自定义修整的内容源创建一个爬网规则。您可以通过“搜索管理”站点执行此操作。
  4. 使用 Windows PowerShell cmdlet New-SPEnterpriseSearchSecurityTrimmer 在爬网规则中注册修整器。
  5. 针对与您在步骤 3 中创建的爬网规则相关联的内容源,执行完全爬网 操作。若要正确更新所有相关的数据库表,必须执行完全爬网操作。增量爬网不会更新适当的表。

实现自定义安全修整器接口

MOSS 2007 和 Microsoft Search Server (MSS) 2008 通过 ISecurityTrimmer 接口支持对搜索结果进行自定义安全修整。此接口有两个方法:Initialize 和 CheckAccess。因为 SharePoint 中体系结构的更改,以及 2010 版中的搜索系统,这两个方法已不再像在 MOSS 2007 中那样有效。需要使用 ISecurityTrimmer2 接口重新实现这两个方法。因此,如果您尝试在 SharePoint 2010 中注册 MOSS 2007 修整器,将会失败,并说明没有实现 ISecurityTrimmer2。自 MOSS 2007 以来的其他更改包括:

Initialize 方法中的更改 在 MOSS 2007 中,传递的某个参数是 SearchContext 对象。SearchContext 是搜索系统的入口点,并为站点或搜索服务提供程序 (SSP) 提供搜索上下文。这个类在 2010 中已被弃用,而改为使用 SearchServiceApplication 类:

void Initialize(NameValueCollection staticProperties, SearchServiceApplication searchApplication);

CheckAccess 方法中的更改 在 MOSS 2007 和 SharePoint 2010 中,搜索查询服务调用 CST 程序集。在 MOSS 2007 中,CheckAccess 方法仅使用两个参数,但是在 SharePoint 2010 中,搜索查询服务使用第三个参数(类型为 IIdentity)将用户标识传递给 CheckAccess:

public BitArray CheckAccess(IList<String>documentCrawlUrls, IDictionary<String, Object>sessionProperties, IIdentity passedUserIdentity)

ISecurityTrimmer2::Initialize 方法 在第一次将修整器加载到搜索查询服务 IIS 工作进程中时,调用这个方法。程序集在整个工作进程生存期内都有效。下面是此方法的签名,以及解释其工作原理的说明:

void Initialize(NameValueCollection staticProperties, SearchServiceApplication searchApplication);

staticProperties - 修整器注册 Windows PowerShell cmdlet (New-SPEnterpriseSearchSecurityTrimmer) 使用一个名为“properties”的参数(在 MOSS 2007 中这个参数名为“configprops”),用于传递以 ~ 分隔的命名值对。这对于初始化修整器类属性可能很有用。

例如,将“superadmin~foouser~poweruser~baruser”传递给 New-SPEnterpriseSearchSecurityTrimmer cmdlet 时,NameValueCollection 参数在集合中将会有两个项,其键分别为“superadmin”和“poweruser”,值分别为“foouser”和“baruser”。

searchApplication - 如果修整器需要对搜索服务实例和 SharePoint 场有更深的了解,可以使用 searchApplication 对象来确定这些信息。若要了解有关 SearchServiceApplication 类的详细信息,请参见 msdn.microsoft.com/library/ee573121(v=office.14)

ISecurityTrimmer2::CheckAccess 方法 此方法用于实现所有的修整逻辑。此方法有两个方面需要特别注意:发出查询的用户的标识,以及由大型返回查询集造成的性能延迟。

下面是此方法的签名,以及解释其工作原理的说明:

public BitArray CheckAccess(IList<String>documentCrawlUrls, IDictionary<String, Object>sessionProperties, IIdentitypassedUserIdentity)

documentCrawlUrls - 准备由此修整器进行安全修整的 URL 集合。

sessionProperties - 每个查询实例将被视为一个会话。如果您的查询获取了很多结果,就会多次调用 CheckAccess 方法。您可以使用这个参数在多次调用之间共享值,或者跟踪处理过的 URL。

passedUserIdentity - 这是发出查询的用户的标识。代码会根据此标识来允许或拒绝对内容的访问。

BitArray - 您需要返回一个位数组,其值应该等于 documentCrawlUrls 中的项数。将此数组中的位设置为 true 或 false,将会决定是允许还是阻止处于该位置的 URL 显示在返回给用户的最终结果集中。

UserIdentity SharePoint 2010 搜索查询引擎是构建在声明身份验证模式上的。搜索查询服务会通过 IIdentity 参数传递查询发出者的声明。若要获得发出查询的用户的用户名,您必须遍历整个声明集合,将 claim.ClaimType 与 SPClaimTypes.UserLogonName 进行比较。

以下代码片段从声明令牌中提取出用户登录名:

IClaimsIdentity claimsIdentity = (IClaimsIdentity)passedUserIdentity;

if (null != claimsIdentity)
{
  foreach (Claim claim in claimsIdentity.Claims)
  {
    if (claim == null)
      continue;
    if (SPClaimTypes.Equals(claim.ClaimType, SPClaimTypes.UserLogonName))
      strUser = claim.Value;
  }
}

您可能需要有关在网站集合级别使用的身份验证类型的信息,才能正确调用内部 API。若要识别用户是否使用 Windows 身份验证进行登录,请查找是否存在 ClaimsType.PrimarySid。以下代码用于查找 PrimarySid 声明,然后从中提取用户名:

if (SPClaimTypes.Equals(claim.ClaimType, ClaimTypes.PrimarySid))
{
  // Extract SID in the format "S-1-5-21-xxxxx-xxxxx-xxx"
  strUser = claim.Value;
  // Convert SID into NT Format "FooDomain\BarUser"
  SecurityIdentifier sid = new SecurityIdentifier(strUser);
  strUser = sid.Translate(typeof(NTAccount)).Value;
}

对于窗体或其他类似的非 Windows 身份验证提供程序,请查看声明内的 Claim.OriginalIssuer 值。例如,如果服务器配置为使用 ASP.NET SQL 成员资格提供程序的窗体身份验证,Claim.OriginalIssuer 的值将为“Forms:AspNetSqlMembershipProvider”:

if (SPClaimTypes.Equals(claim.ClaimType, SPClaimTypes.UserLogonName))
{
  strUser = claim.Value;
  strProvider = claim.OriginalIssuer; // For AspNet SQL Provider value will be
                                      // "Forms:AspNetSqlMembershipProvider"
}

如果查询是匿名用户发出的,IIdentity.IsAuthenticated 方法的值将为 false。在这种情况下,claimsIdentity.Name 的值将为“NT AUTHORITY\\ANONYMOUS LOGON”。

关于用户上下文的最后一点是,仅将 API WindowsIdentity.GetCurrent().Name 用来检索用户标识。此操作会提供应用程序池标识,而搜索查询服务正是在这个应用程序池中运行。System.Threading.Thread.CurrentPrincipal.Identity 会为您提供与传递给 CheckAccess 方法相同的标识。

性能注意事项 最大限度地优化 CheckAccess 方法。如果查询返回了许多结果,修整器可能会被调用多次。处理这种情况的常用方法之一就是通过 sessionProperties 参数跟踪修整器内部处理过的 URL。一旦方法处理了一定数量的结果集,就会引发 PluggableAccessCheckException。当此异常被引发后,到该时间点为止处理过的所有 URL 就会返回给用户。

自定义安全修整器和系统日志

修整器内部的代码无法写入位于以下路径的系统日志:<驱动器>\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\LOGS。修整器必须维护自己的日志记录机制,以用于调试和审核。唯一的例外就是当方法引发 PluggableAccessCheckException 时。引发此异常时指定的消息字符串会记录到系统日志中。搜索查询服务记录到文件中的有用信息包括经过安全修整的文档数量。例如,以下日志项表明某个查询传递了两个文档给 CST,但是返回给用户的文档数是零,这意味着 CST 修整了这两个文档:

04/23/2010 18:13:48.67    w3wp.exe (0x116C)    0x02B4    SharePoint Server Search    Query Processor    dm2e    Medium    Trim results: First result position = '0', actual result count = '0', total docs found = '0', total docs scanned = '2'.    742d0c36-ea37-4eee-bf8c-f2c662bc6a45

自定义安全修整器和警报 SharePoint 搜索服务有一项称为警报 的功能(只在 Windows 身份验证模式下可用),能够将查询结果中的更改通过电子邮件推送给用户。然而,当计时器服务发出警报查询时,搜索查询服务会将所有与 CST 相关联的 URL 剥离。

程序集签名要求 在查找匹配的 CST 时,搜索查询服务会调用 CST 管理代码,以从 GAC 加载特定的程序集。为此,程序集需要进行数字签名。有关如何为程序集签名的信息,请参见“管理程序集签名和清单签名”(msdn.microsoft.com/library/ms247066)。生成程序集之后,使用 sn.exe 工具获得 64 位哈希,也就是通常所说的公钥令牌。在修整器注册时会需要此令牌。

自定义安全修整器的部署 CST 程序集必须位于运行搜索查询和站点设置服务的每台计算机的 GAC 中。使用“管理中心”|“系统设置”|“服务器上的服务”可以检查场中每台计算机上的搜索查询和站点设置服务的状态。如果服务已经启动,您必须将 CST 导入那台计算机。不要将搜索查询和站点设置服务与包含查询组件的计算机混为一谈。查询组件位于 MSSearch.exe 中,用于将结果从索引中取出来。搜索查询和站点设置服务位于其自己的 IIS 工作进程 w3wp.exe 中。

用于注册、查看和删除 CST 的 SharePoint Cmdlet

MOSS 2007 使用 stsadm.exe 命令行工具来注册自定义修整器。但是这个工具已过时,并且在 SharePoint 2010 中不再支持。因此改为使用 Windows PowerShell cmdlet 来注册、查看和删除 CST。在 GAC 中应当已经有一个程序集,用来进行注册。以下是这些工具的使用方法:

注册 - 通过程序集的清单数据(例如 Version、Culture 和 PublicKeyToken),使用 New-SPEnterpriseSearchSecurityTrimmer 注册修整器。以下示例将修整器注册到名为“Search Service Application”的搜索应用程序:

New-SPEnterpriseSearchSecurityTrimmer -SearchApplication "Search Service Application" -TypeName "SearchCustomSecurityTrimmer.CustomSecurityTrimmerTest, SearchCustomSecurityTrimmer, Version=14.0.0.0, Culture=neutral, PublicKeyToken=4ba2b4aceeb50e6d" -RulePath file://elenjickal2/* -id 102 -Properties superadmin~foouser~poweruser~baruser

Cmdlet 使用了爬网规则 (RulePath)、整数值的修整器标识 (id)、配置属性 (properties) 和 TypeName(由清单数据以及用于实现接口的类的名称组成)。Cmdlet 参数包括:

  • SearchApplication - 与内容源相关联的搜索服务应用程序的名称
  • TypeName - 由清单数据构成,例如 Version、Culture 和 PublicKeyToken(它还指向用于实现接口的类;这将在 GAC 中唯一标识程序集)
  • RulePath - 与修整器相关联的爬网规则
  • Id - 一个 int 数据类型,用于唯一标识修整器实例
  • Properties - 由 ~ 分隔的名称/值对集

查看 - 使用 Get-SPEnterpriseSearchSecurityTrimmer cmdlet 并传递搜索应用程序名称。您可以通过传递修整器标识或注册时使用的其他属性进一步进行筛选(例如:Get-SPEnterpriseSearchSecurityTrimmer -SearchApplication "Search Service Application")。

删除 - 使用 Remove-SPEnterpriseSearchSecurityTrimmer cmdlet 并传递搜索应用程序名称和修整器标识(例如:Remove-SPEnterpriseSearchSecurityTrimmer -SearchApplication "Search Service Application" –id 102)。

注意:注册完 CST 之后,需要对内容源进行完全爬网。

故障排除步骤

下面是一些提示,用于调查任何意外的搜索结果:

  • 确保爬网规则与内容源的位置相匹配。
  • 检查爬网日志,确保用于对内容源进行爬网的帐户有权访问这些内容源。如果没有访问权限,爬网操作就会失败。
  • 确保查询用户有权查看内容。
  • 修整器注册完之后,确保执行了完全爬网操作。
  • 确保运行搜索查询服务的所有计算机的 GAC 中都有修整器程序集。
  • 检查系统日志,查看安全修整器修整过的文档数量。
  • 使用实用工具 ProcessExplorer (technet.microsoft.com/sysinternals/bb896653) 来确保修整器程序集加载到了 IIS 工作进程 w3wp.exe 中。
  • 将调试器连接到加载了程序集的工作进程,并逐步调试修整器逻辑。

查询处理逻辑的灵活性

总之,CST 提供了一定的灵活性,可以扩展查询处理逻辑,使其满足自定义的企业安全需要。请始终谨记,修整器内部的实现错误可能会导致意外的搜索结果,因此在生产环境中部署修整器之前,务必将修整器与不同类型的内容源和身份验证提供程序结合进行完全测试。

Ashley Elenjickal 和 Pooja Harjani* 是 Microsoft SharePoint 搜索功能团队的成员,负责自定义安全修整器。您可以通过电子邮件 AshleyEl@microsoft.comPVaswani@microsoft.com,分别与他们联系。*

衷心感谢以下技术专家审阅本文:Michal Piaseczny