次の方法で共有



July 2010

Volume 25 Number 07

SharePoint セキュリティ - セキュリティを強化するための SharePoint 検索結果のトリミング

Ashley Elenjickal | July 2010

コード サンプルのダウンロード

Microsoft SharePoint の検索では、通常、リポジトリ全体に完全な読み取りアクセス権のあるアカウントを使用して、コンテンツのインデックスを作成します。そのため、ユーザーがなんらかのコンテンツを照会する際に、閲覧権限のあるドキュメントしか表示できないように制限することが重要です。SharePoint では、各ドキュメントに関連付けられたアクセス制御リスト (ACL) を使用して、ユーザーに閲覧権限がない照会結果をトリミングして、取り除きます。ただし、SharePoint で使用できる既定のトリミング (組み込みのトリミング) では、必ずしも、データ セキュリティのニーズを十分満たせるとは限りません。このような場合は、組織の認証構造に応じて、結果をさらにトリミングすることになります。

ここで、SharePoint カスタム セキュリティ トリミング インフラストラクチャが役に立ちます。SharePoint では、ビジネス ロジックを個別のモジュールに実装してから、クエリを処理するクエリ プロセッサのワークフローにそのビジネス ロジックを統合することができます。セキュリティ トリミングのパスでは、カスタム クエリ トリミングは、組み込みのセキュリティ トリミングの後に実行されます。そのため、カスタム トリミング後のクエリ結果数は、カスタム セキュリティ トリマー (CST) アセンブリを登録する前に検索されたドキュメント数と同じか、それよりも少なくなります。

CST アーキテクチャについて詳しく説明する前に、SharePoint 検索と新しいクレーム認証インフラストラクチャについて簡単に紹介します。

SharePoint 検索の概要

検索システムは、大まかに、収集パイプラインとクエリ プロセッサ パイプラインの 2 つに分けることができます。

収集パイプライン: SharePoint サイト、HTTP サイト、ファイル共有、Lotus Notes、Exchange Server など、さまざまなリポジトリからコンテンツをクロールして、インデックスを作成します。このコンポーネントは MSSearch.exe の内部で実行されます。リポジトリのクロール要求が行われると、収集パイプラインは、フィルター デーモン (MssDmn.exe) を呼び出し、必要なプロトコル ハンドラーと、コンテンツに接続、フェッチ、および解析するのに必要なフィルターを読み込みます。図 1 は、収集パイプラインを簡単に表したものです。

SharePoint の収集パイプラインの概要

図 1 SharePoint の収集パイプラインの概要

SharePoint では、Windows NTLM 認証アカウントを使用する場合は、クロールのみ実行できます。コンテンツ ソースでは、ドキュメント コンテンツにアクセスするために、クロール要求の一部として送信された Windows アカウントを承認しなければなりません。クレーム認証は SharePoint 2010 でサポートされていますが、収集パイプラインはまだクレーム対応のアプリケーションではないため、クレーム認証のみを使用しているコンテンツ ソースにはアクセスしません。

クエリ プロセッサ パイプライン: SharePoint 2010 では、トポロジ上のスケーラビリティと認証モデルの 2 つに関して、クエリ プロセッサ パイプラインに重要な変更が加えられています。つまり、Microsoft SharePoint Server (MOSS) 2007 では、クエリ プロセッサ (検索クエリとサイト設定のサービスのことで、これ以降は検索クエリ サービスと呼びます) は、Web フロント エンド (WFE) と同じプロセスで実行されていましたが、SharePoint 2010 では、ファーム内であればどこでも実行でき、Web サービスとしても実行されるようになります。

WFE は、Windows Communication Foundation (WCF) 呼び出しを通じて、検索クエリ サービスと対話します。検索クエリ サービスは、SharePoint クレーム認証インフラストラクチャの上位に完全に構築されるようになります。そのため、SharePoint 検索は、Windows 認証とフォーム認証とは密接に統合されません。その結果、さまざまな認証モデルをサポートするようになりました。検索クエリ サービスは、クエリを発行するユーザーの権限に応じて、検索結果をトリミングします。カスタム セキュリティ トリマーは、組み込みのトリミングの完了後に検索クエリ サービスから呼び出されます。図 2 には、クエリを実行する際に関連するさまざまなコンポーネントを示しています。

SharePoint サイトの検索センターから発行されるクエリのワークフロー

図 2 SharePoint サイトの検索センターから発行されるクエリのワークフロー

カスタム セキュリティ トリミングは、クエリ プロセッサ パイプラインの一部なので、クエリ プロセッサ パイプラインのコンポーネントに的を絞って説明しましょう。

SharePoint 2010 におけるクレーム認証

CST アセンブリ内に、カスタム トリミング ロジックを実装するには、SharePoint 2010 のクレーム認証サポートの基本を理解する必要があります。クレーム認証対応の環境では、ユーザー ID はセキュリティ トークンと呼ばれるエンベロープ内部で管理されます。このセキュリティ トークンには、ユーザーに関する ID アサーションやクレームのコレクションが含まれています。クレームの例には、ユーザー名、電子メール アドレス、電話番号、役割などがあります。各クレームには、"型"、"値" など、さまざまな属性があります。たとえば、クレームでは、UserLogonName は "型" で、現在ログインしてるユーザーの名前は "値" と考えられます。

セキュリティ トークンは、セキュリティ トークン サービス (STS) というエンティティから発行されます。STS は、ユーザー認証の要求に応答する Web サービスです。ユーザーが認証されると、STS はそのユーザーの権利をすべて含むセキュリティ トークンを送信します。STS は、同じ SharePoint ファームに存在するように構成したり、ファームの外に存在する別の STS の証明書利用者として動作するように構成したりできます。前者は ID プロバイダー STS (IP-STS)、後者は証明書利用者 STS (RP-STS) と呼ばれます。IP-STS と RP-STS のどちらを使用するかは、SharePoint の展開を設計する際、注意深く検討する必要があります。

SharePoint では、製品に含まれ、簡単にインストールして利用できる、既定のクレーム プロバイダーを使用します。Windows 認証を使用してファームを完全に設定した場合でも、クエリを発行する際、検索サービス アプリケーション プロキシは、セキュリティ トークンに含まれるユーザーのクレームをすべて抽出するように STS に指示します。このセキュリティ トークンは、その後、WCF 呼び出しを通じて、検索クエリ サービスに渡されます。

カスタム セキュリティ トリミングのワークフロー

CST のワークフロー ロジックは、図 3 に示すような単純なフローチャートで表すことができます。

CST のワークフロー ロジック

図 3 CST のワークフロー ロジック

既に説明したように、検索クエリ サービスは、まず、組み込みのセキュリティ トリミングを実行してから、検索結果に関連付けられた CST があるかどうかを確認します。特定のコンテンツ ソースを CST と関連付けるには、その特定のコンテンツ ソースに関する "クロール ルール" を定義します。検索クエリ サービスは、検索結果内に URL と関連付けられた CST を検出すると、そのトリマーを呼び出します。トリマーは、検索クエリ サービスを実行しているのと同じ IIS ワーカー プロセス (w3wp.exe) に読み込まれます。

トリマーが読み込まれたら、検索クエリ サービスは、先ほど定義したクロール ルールに関連付けられた、"組み込みトリミング" の結果セットを指定して、トリマー内に実装されている CheckAccess メソッドを呼び出します。CheckAccess メソッドでは、ユーザーに送信する最後の結果セットに、具体的な URL を含めるかどうかを決定します。この処理は、ビット配列を返すことによって行います。この配列内のビットに true または false を設定することで、最後の結果セットに URL を "含める" か "ブロックする" かを指定します。パフォーマンス上の理由、または予期しない理由によって、URL の処理を停止する場合は、PluggableAccessCheckException をスローする必要があります。URL の一覧を部分的に処理した後でこの例外をスローすると、それまでに処理済みの結果がユーザーに送信されます。検索クエリ サービスは、最終結果セットから、未処理の URL をすべて削除します。

カスタム セキュリティ トリマーの展開に必要な手順

一言で言えば、CST を適切に展開するには、次の 5 つの手順を実行します。

  1. ISecurityTrimmer2 インターフェイスを実装します。
    1. マネージ コードを使用して、Initialize メソッドと CheckAccess メソッドを実装します。
    2. アセンブリ署名ファイルを作成して、プロジェクトの一部として含めます。
    3. アセンブリをビルドします。
  2. 検索クエリ サービスを実行しているすべてのコンピューターのグローバル アセンブリ キャッシュ (GAC) に、トリマーを展開します。
  3. カスタム トリミングを実行するコンテンツ ソースのクロール ルールを作成します。検索管理サイトから作成できます。
  4. Windows PowerShell コマンドレットの "New-SPEnterpriseSearchSecurityTrimmer" を使用して、クロール ルールにトリマーを登録します。
  5. 手順 3. で作成したクロール ルールと関連付けられたコンテンツ ソースの "フル クロール" を実行します。フル クロールは、関連データベース テーブルをすべて適切に更新するのに必要です。増分クロールでは、適切なテーブルが更新されません。

カスタム セキュリティ トリマー インターフェイスの実装

MOSS 2007 と Microsoft Search Server (MSS) 2008 では、ISecurityTrimmer インターフェイスを通じて、検索結果のカスタム セキュリティ トリミングをサポートしていました。このインターフェイスには、Initialize と CheckAccess の 2 つのメソッドがあります。SharePoint と、MOSS 2010 と MSS 2010 の検索システムのアーキテクチャ上の変更により、この 2 つのメソッドは、MOSS 2007 と同じようには機能しません。ISecurityTrimmer2 インターフェイスを使用して、実装しなおす必要があります。そのため、SharePoint 2010 に MOSS 2007 のトリマーを登録しようとしても、ISecurityTrimmer2 が実装されていないことを示すメッセージが表示されて失敗します。MOSS 2007 からの変更は次のとおりです。

Initialize メソッドの変更: MOSS 2007 では、SearchContext オブジェクトをパラメーターの 1 つとして渡していました。SearchContext オブジェクトは、検索システムへのエントリ ポイントで、サイトの検索コンテキストや検索サービス プロバイダー (SSP) を提供します。このクラスは MOSS 2010 では廃止され、SearchServiceApplication クラスが使用されます。

void Initialize(NameValueCollection staticProperties, SearchServiceApplication searchApplication);

CheckAccess メソッドの変更: MOSS 2007 および SharePoint 2010 では、検索クエリ サービスは CST アセンブリを呼び出します。MOSS 2007 の CheckAccess メソッドは、パラメーターを 2 つしか受け取りませんでしたが、SharePoint 2010 の検索クエリ サービスは、IIdentity 型の 3 つ目のパラメーターを使用して、ユーザー ID を 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 コマンドレットの New-SPEnterpriseSearchSecurityTrimmer は、"properties" というパラメーターを受け取ります (MOSS 2007 では "configprops" でした)。このパラメーターを使用して、名前と値のペアを ~ で区切って渡すことができます。これは、トリマー クラスのプロパティを初期化するのに役立つ場合があります。

たとえば、次のように記述します。"superadmin~foouser~poweruser~baruser" を New-SPEnterpriseSearchSecurityTrimmer コマンドレットに渡すと、NameValueCollection パラメーターには、キーが "superadmin" と "poweruser" で、値が "foouser" と "baruser" の 2 つの項目がそれぞれコレクション内に含まれることになります。

"searchApplication": トリマーで、検索サービス インスタンスと SharePoint ファームに関する詳細情報を必要としている場合、searchApplication オブジェクトを使用して、この情報を決定します。SearchServiceApplication クラスの詳細については、msdn.microsoft.com/library/ee573121(v=office.14) 英語) を参照してください。

ISecurityTrimmer2 の CheckAccess メソッド: このメソッドを使用して、トリミング ロジックをすべて実装します。このメソッドでは、次の 2 点について特に注意してください。1 つは、クエリを発行したユーザーの ID、もう 1 つはクエリ セットが大量に返されることによる待機時間に関するパフォーマンスです。

次のコードは、このメソッドのシグネチャと、そのしくみを示します。

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

"documentCrawlUrls": このトリマーによってセキュリティ トリミングが行われる URL のコレクションです。

"sessionProperties": 単一のクエリ インスタンスを、1 つのセッションとして扱います。クエリが多くの結果をフェッチする場合、CheckAccess メソッドが複数回呼び出されます。このパラメーターを使用して、値を共有したり、複数回の呼び出しの間に処理される URL を追跡したりできます。

"passedUserIdentity": クエリを発行したユーザーの ID です。この ID を使用して、コードからコンテンツへのアクセスを許可または拒否できます。

"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" という値が含まれます。

ユーザー コンテキストに関する最後の注意事項として、ユーザー ID を取得する場合、API の WindowsIdentity.GetCurrent().Name を使用するように制限します。そうすれば、常に、検索クエリ サービスを実行しているアプリケーション プール ID が取得されます。System.Threading.Thread.CurrentPrincipal.Identity では、CheckAccess メソッドに渡されるものと同じ ID が取得されます。

パフォーマンスの考慮事項: CheckAccess メソッドをできる限り最適化します。クエリが結果をたくさん返す場合、トリマーが複数回呼び出されることがあります。このような状況に共通する方法の 1 つは、sessionProperties パラメーターを使用して、トリマー内部で処理される URL を追跡することです。この方法で、ある程度の結果セットを処理したら、PluggableAccessCheckException をスローできます。この例外をスローすると、その時点までに処理済みの URL がユーザーに返されます。

カスタム セキュリティ トリマーとシステム ログ

トリマー内部のコードからは、<ドライブ>\ Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\LOGS で管理されているシステム ログに書き込むことはできません。トリマーでは、デバッグと監査を行うために、固有のログ メカニズムを管理する必要があります。唯一の例外は、メソッドで PluggableAccessCheckException をスローする場合です。
スローするときに指定したメッセージ文字列は、システム ログに記録されます。検索クエリ サービスによってファイルに記録される有益な情報には、セキュリティ トリミングを実行したドキュメントの数などがあります。たとえば、次のログ エントリからは、クエリにより 2 つのドキュメントが CST に渡されたものの、ユーザーにはドキュメントが 1 つも送信されていないことがわかります。これはつまり、CST でこれらの 2 つのドキュメントがトリミングされたことになります。

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 に存在する必要があります。[Central Administration] (サーバーの全体管理)、[System Settings] (システム設定)、[Manage services on server] (サーバーのサービスの管理) を順にクリックして、ファームの各コンピューターの検索クエリとサイト設定のサービスを確認します。サービスが開始したら、CST を対象のコンピューターにインポートする必要があります。検索クエリとサイト設定のサービスを、クエリ コンポーネントを含むコンピューターと混同しないように注意してください。クエリ コンポーネントは MSSearch.exe 内に存在し、インデックスから結果を取り出します。検索クエリとサイト設定のサービスは、w3wp.exe の独自の IIS ワーカー プロセスに存在します。

CST を登録、表示、および削除するための SharePoint コマンドレット

MOSS 2007 では、stsadm.exe コマンド ライン ツールを使用して、カスタム トリマーを登録していましたが、このツールは廃止され、SharePoint 2010 ではサポートされません。代わりに、SharePoint 2010 では Windows PowerShell コマンドレットを使用して、CST を登録、表示、および削除します。CST を登録するには、アセンブリが既に GAC 内で使用可能になっている必要があります。使用方法を次に示します。

"登録": 「New-SPEnterpriseSearchSecurityTrimmer」を使用して、トリマーを登録します。この際、Version、Culture、PublicKeyToken などのアセンブリのマニフェスト データを使用します。次の例では、"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

コマンドレットは、クロール ルール (RulePath)、トリマーの ID となる整数値 (id)、構成プロパティ (Properties)、および TypeName を受け取ります。TypeName はマニフェスト データと、インターフェイスを実装するクラスの名前で構成されます。コマンドレットのパラメーターは次のとおりです。

  • SearchApplication: コンテンツ ソースに関連付けられた検索サービス アプリケーションの名前です。
  • TypeName: Version、Culture、PublicKeyToken などのマニフェスト データから構成されます (また、インターフェイスを実装するクラスを指します。これで、GAC からアセンブリを一意に識別します)。
  • RulePath: トリマーに関連付けられるクロール ルールです。
  • Id: トリマー インスタンスを一意に識別する int データ型のデータです。
  • Properties: ~ で区切られた名前と値のペアのセットです。

"表示": 「Get-SPEnterpriseSearchSecurityTrimmer」コマンドレットを使用して、検索アプリケーション名を渡します。登録の際にも使用した トリマー ID やその他のプロパティを渡して、さらにフィルター処理できます (たとえば、「Get-SPEnterpriseSearchSecurityTrimmer -SearchApplication "Search Service Application"」のように指定します)。

"削除": 「Remove-SPEnterpriseSearchSecurityTrimmer」コマンドレットを使用して、検索アプリケーション名とトリマーの ID を渡します (たとえば、「Remove-SPEnterpriseSearchSecurityTrimmer -SearchApplication "Search Service Application" –id 102」のように指定します)。

注: CST を登録したら、コンテンツ ソースのフル クロールが必要になります。

トラブルシューティング手順

予期しない検索結果を調査する際のヒントを次にいくつか紹介します。

  • クロール ルールとコンテンツ ソースの場所が一致するようにします。
  • クロール ログを確認して、コンテンツ ソースをクロールするために使用するアカウントで、コンテンツ ソースにアクセスできるようにします。アクセスできないと、クロールは失敗します。
  • クエリ ユーザーがコンテンツを閲覧するアクセス権を持つようにします。
  • トリマーの登録後、フル クロールを実行するようにします。
  • 検索クエリ サービスを実行しているすべてのコンピューターの GAC に、トリマーのアセンブリが存在するようにします。
  • セキュリティ トリマーによってトリミングされたドキュメント数について、システム ログを確認します。
  • ProcessExplorer ユーティリティ (technet.microsoft.com/sysinternals/bb896653) を使用して、トリマー アセンブリが IIS ワーカー プロセス (w3wp.exe) に読み込まれるようにします。
  • アセンブリが読み込まれているワーカー プロセスにデバッガーをアタッチし、トリマー ロジックをステップ スルーします。

クエリ処理ロジックの柔軟性

以上をまとめると、CST の柔軟性により、クエリ処理ロジックを拡張して、企業全体のセキュリティのニーズに合うようにカスタマイズできます。トリマー内の実装に関するバグが原因で、予期しない検索結果が発生する可能性があることに、常に注意する必要があります。そのため、トリマーを運用環境に展開する前に、さまざまな種類のコンテンツ ソースや認証プロバイダーに対して、十分なテストを実行する必要があります。

Ashley Elenjickal および Pooja Harjani は、マイクロソフトの SharePoint 検索機能チームのメンバーで、カスタム セキュリティ トリマーを担当していました。2 人の連絡先はそれぞれ、AshleyEl@microsoft.com (英語のみ) と PVaswani@microsoft.com (英語のみ) です。

この記事のレビューに協力してくれた技術スタッフの Michal Piaseczny に心より感謝いたします。