クレームに関するチュートリアル: SharePoint 2010 のクレーム プロバイダーを記述する

概要:  クレームを拡張し、名前解決を提供するクレーム プロバイダーを記述する方法について説明します。クレーム認証を使用して、ユーザーがだれか、あるいはユーザーがどのように認証されるかを知らなくても、クレームに基づいて権限を割り当てることができます。知る必要があるのはユーザーの属性のみです。

最終更新日: 2012年5月31日

適用対象: Business Connectivity Services | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

この記事の内容
クレーム プロバイダーの概要
パート 1: クレームの拡張とプロバイダーの登録
パート 2: 階層ノードのサポートの追加
パート 3: クレームの検索
パート 4: 名前解決のサポート
まとめ
その他の技術情報

提供元:  Steve Peschka、Microsoft Corporation

目次

  • クレーム プロバイダーの概要

  • パート 1: クレームの拡張とプロバイダーの登録

  • パート 2: 階層ノードのサポートの追加

  • パート 3: クレームの検索

  • パート 4: 名前解決のサポート

  • まとめ

  • その他の技術情報

クリックしてコードを取得  ダウンロード コード: SqlClaimsProvider_MSDNExample.zip (英語)

クレーム プロバイダーの概要

Microsoft SharePoint 2010 のクレーム プロバイダーは、クレームを発行します。また、クレームをセキュリティ トークン、つまりユーザーのトークンにパッケージ化します。ユーザーのトークンは、ユーザーが Microsoft SharePoint Foundation 2010 または Microsoft SharePoint Server 2010 にサインインするときに検証され、ユーザーはそのトークンを使用して SharePoint にサインインします。

SharePoint 2010 のクレーム プロバイダーは、主に 2 つの理由から使用されます。

  • クレームを拡張する

  • 名前解決を提供する

クレーム拡張は、クレーム認証サイトにログオンした後で発生する過程の一部です。以下の要素が SharePoint 2010 のクレーム認証時に実行される点に注意してください。

  • Windows クレーム (NTLM あるいは Kerberos プロトコルでログオンした場合)

  • フォーム ベースの認証クレーム (ASP.NET メンバーシップとロール プロバイダーを使用した場合)

  • Security Assertion Markup Language (SAML) クレーム (Active Directory Federation Services (AD FS) 2.0 のような Security Token Service (STS) を使用してログオンした場合)

ログオンした後で、すべての登録済みクレーム プロバイダーがその Web アプリケーションで開始されます。クレーム プロバイダーが開始されたとき、それらはログオン時に提供されなかったクレームを追加することができます。たとえば、ユーザーが Windows 認証を使用してログオンしたとします。しかし、そのユーザーが SAP システムにアクセスするための追加の権利を与える必要が出たとします。このような場合に、クレーム拡張を使用します。

名前解決には、ユーザー選択ウィンドウ コントロールと入力コントロールの 2 つの要素があります。ユーザーがクレームを検索し見つけることができるようにする場合、クレーム プロバイダーでは、ユーザー選択ウィンドウを使用することでこれを可能にします。入力コントロールでは、ユーザー名、あるいはクレームを入力して、次に解決ボタンをクリックします。クレーム プロバイダーはその入力を確認し、それが有効か確認します。入力が有効の場合、クレーム プロバイダーはそれを解決するために "最良の方法" を実行します。

クレーム プロバイダーの機能を抽象的に説明しましたが、次にカスタムのクレーム プロバイダーを構築するために使用するシナリオについて説明します。このシナリオでは、ある人物のひいきのバスケットボール チームに基づいて、サイト コレクションでの権限を割り当てることにします。これはよく理解しておく必要がある、クレーム認証の優れた機能の 1 つです。ユーザーが実際にだれか、またユーザーがサイトで認証される方法は関係ありません。唯一の問題はユーザーの属性であり、この場合は、ユーザーのひいきのチームです。

この Web アプリケーションでは、Windows クレームおよびフォーム ベース認証の両方を有効にします。フォーム ベースの認証ユーザーには標準の SQL メンバーシップとロール プロバイダーを使用し、フォーム ベースの認証アカウントのリストにはあらかじめ user1 から user50 が含まれています。シナリオを単純化するために、ユーザーのひいきのチームは以下の方法で決定されます。

  • すべての Windows ユーザーのひいきのチームは、Consolidated Messenger です。

  • フォーム ベースの認証ユーザーでは以下のとおりです。

    • user1 から user15 のひいきのチームは、Consolidated Messenger です。

    • user16 から user30 のひいきのチームは、Wingtip Toys です。

    • user31 から user50 のひいきのチームは、Tailspin Toys です。

パート 1: クレームの拡張とプロバイダーの登録

最初にすべきことはクレーム拡張です。前述のように、ユーザーが認証された後で、クレーム プロバイダーは有効になります。ユーザー トークンに (どのバスケットボール チームがひいきかという) クレームを追加するには、すでに定義したルールを使用します。

クレーム プロバイダーを記述するには、以下の手順を使用します。この例では、クラス ライブラリ アプリケーションを作成するために Microsoft Visual Studio 2010 を使用します。

手順 1: 参照を追加する

最初に、Microsoft.SharePoint と Microsoft.IdentityModel に参照を追加します。Microsoft.SharePoint.dll は、SharePoint のインストールに含まれています。Microsoft.IdentityModel.dll は、Windows Identity Foundation の一部としてインストールされています。以下は、このインストール環境での Microsoft.IdentityModel.dll の完全パスの例です。

<drive>:\Program Files\Reference Assemblies\Microsoft\Windows Identity Foundation\v3.5\Microsoft.IdentityModel.dll

手順 2: using ステートメントとクラス継承を追加する

参照を追加した後で、using ステートメントを追加し、クラスが継承する基本クラスを定義する必要があります。この例では、以下の using ステートメントを使用します。

using Microsoft.SharePoint.Diagnostics;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Claims;
using Microsoft.SharePoint.WebControls;

ここでのクラスは SPClaimProvider 基本クラスから継承する必要があります。以下のコードは、クラスの最初の状態を示します。SqlClaimsProvider という名前に注意してください。このコードは、当初、SQL メンバーシップとロール プロバイダーでのみ使用するために記述しようとしていましたが、後で Windows でも使用できるようにしました。

namespace SqlClaimsProvider
{
    public class SqlClaims : SPClaimProvider
    {

        public SqlClaims(string displayName)
            : base(displayName)
        {
        }
    }
}

手順 3: 必要な実装を追加する

実装する必要があるすべてのインターフェイスを手順ごとにチェックする代わりに、このコードでは、SPClaimProvider 名で一時停止し、S 下に表示されるドロップダウン矢印をクリックして、[抽象クラス 'SPClaimProvider' を実装する] コマンドを選択することができます。

手順 4: プロバイダーに含まれる機能を実装する

次に行う操作にかかわらず、抽象クラスを実装した後で、SPClaimProvider クラスに、Name、SupportsEntityInformation、SupportsHierarchy、SupportsResolve、および SupportsSearch の 5 つのプロパティを実装する必要があります。

最初に、Supports* プロパティについて説明します。クレーム拡張だけをする場合は、サポートする必要があるのはエンティティ情報のみです。クラスのプロパティ リストは以下のようになります。

public override bool SupportsEntityInformation
{
      get 
      { 
            return true; 
      }
}

public override bool SupportsHierarchy
{
      get 
      { 
            return false; 
      }
}

public override bool SupportsResolve
{
      get 
      { 
            return false; 
      }
}

public override bool SupportsSearch
{
      get 
      { 
            return false; 
      }
}

次に、Name プロパティのサポートを実装します。通常、プロバイダーが参照される際に必要な "内部" 名と表示名の両方をサポートします。

この例では、プロジェクトに後で追加する別のクラスと共有できるように、内部静的プロパティを使用します。この実装での Name プロパティは、以下のようになります。

internal static string ProviderDisplayName
{
      get
      {
            return "Basketball Teams";
      }
}


internal static string ProviderInternalName
{
      get
      {
            return "BasketballTeamProvider";
      }
}


public override string Name
{
      get
      {
            return ProviderInternalName;
      }
}

これで、基本的な実装はすべて完了しました。次に、より興味深い事柄を説明します。まず、チームのクレーム プロバイダーで使用するための配列をセットアップします。以下のように、クラスの先頭に追加します。

// Teams that we are using.
private string[] ourTeams = new string[] { "Consolidated Messenger", "Wingtip Toys", "Tailspin Toys " };

次に、クレーム プロバイダーのコアを実装する必要があります。クレーム拡張をするには、SPClaimProvider クラスに FillClaimsForEntity メソッド、FillClaimTypes メソッド、および FillClaimValueTypes メソッドの実装コードを追加します。

始めに、クレーム プロバイダーを作成する際の過程全体で呼び出すために、いくつかの単純なヘルパー関数を作成します。これらのヘルパー関数は、基本的にクレーム名前空間あるいは識別子である ClaimType と、string あるいは int のような、ClaimValueType を定義します。

以下はそのための 2 つのヘルパー関数です。

private static string SqlClaimType
{
      get
      {
            return "http://schema.steve.local/teams";
      }
}

private static string SqlClaimValueType
{
      get
      {
            return Microsoft.IdentityModel.Claims.ClaimValueTypes.String;
      }
}

この時点で、ここから確認できることは、クレーム プロバイダーが機能している場合、http://schema.steve.local/teams という名前のクレームを追加するということ、そしてそのクレームの値が文字列であるということです。

以前のコードと情報から、値が Consolidated MessengerWingtip Toys、あるいは Tailspin Toys のいずれかとなることは分かっています。クレーム名自体については、名前の付け方に関してルールはありません。通常、schemas.SomeCompanyName.com/ClaimName の書式に従います。今回の場合、ドメインは steve.local です。このため、schemas.steve.local を使用し、teams が、このクレームによって追跡管理されるプロパティとなります。

以下のコードのように、実際にそのクレームを追加する部分は、次の、SPClaimProvider クラスの FillClaimsForEntity メソッドになります。

protected override void FillClaimsForEntity(Uri context, SPClaim entity, 
      List<SPClaim> claims)
{
if (entity == null)
      throw new ArgumentNullException("entity");

if (claims == null)
      throw new ArgumentNullException("claims");

// Determine who the user is, so that we know what team to add to their claim
// entity. The value from the input parameter contains the name of the 
// authenticated user. For a SQL forms-based authentication user, it looks similar to
// 0#.f|sqlmembership|user1; for a Windows claims user it looks similar 
// to 0#.w|steve\\wilmaf.
// I will skip some uninteresting code here, to look at that name and determine
// whether it is a forms-based authentication user or a Windows user, and if it is a forms-based authentication user, 
// determine what the number part of the name is that follows "user".

string team = string.Empty;
int userID = 0;
            
// After the uninteresting code, "userID" will equal -1 if it is a Windows user.
// If it is a forms-based authentication user, it will contain the number that follows "user".
            
// Determine what the user's favorite team is.
if (userID > 0)
{
      // Plug in the appropriate team.
      if (userID > 30)
            team = ourTeams[2];
      else if (userID > 15)
            team = ourTeams[1];
      else
            team = ourTeams[0];
}
else
      team = ourTeams[1];  
      // If they are not one of our forms-based authentication users, 
      // make their favorite team Wingtip Toys.
      
// Add the claim.
claims.Add(CreateClaim(SqlClaimType, team, SqlClaimValueType));
}

このメソッドについて重要な点は、コードの最後の行です。ここでは、SPClaim オブジェクトのリストである、入力 claims パラメーターを取ります。CreateClaim ヘルパー メソッドを使用して、新しいクレームを作成します。

ヒントヒント

可能なときは、ヘルパー メソッドを使用するよう強く推奨します。一般的に、既定のコンストラクターを使用するより多機能で、より行き届いた処理ができます。

最後に、クレームを作成するとき、以前に説明した SqlClaimType メソッドと SqlClaimValueType メソッドの 2 つのヘルパー メソッドを使用します。

これで、このコードの最も複雑な部分は完成ですが、次に FillClaimTypes と FillClaimValueTypes の 2 つの追加のメソッドを実装する必要があります。これらのメソッドではヘルパー メソッドを使うだけで済むため、実装は簡単です。実装は以下のようになります。

protected override void FillClaimTypes(List<string> claimTypes)
{
      if (claimTypes == null)
            throw new ArgumentNullException("claimTypes");

      // Add our claim type.
      claimTypes.Add(SqlClaimType);
}

protected override void FillClaimValueTypes(List<string> claimValueTypes)
{
      if (claimValueTypes == null)
            throw new ArgumentNullException("claimValueTypes");

      // Add our claim value type.
      claimValueTypes.Add(SqlClaimValueType);
}

このコードは十分に明白です。そのため、これ以上の説明は不要です。

これで、クレーム拡張をするクレーム プロバイダーの基本的な実装を完了しました。これをどのように使用すればいいでしょうか。推奨の方法は、クレーム機能レシーバーを使用することです。

手順 5: クレーム プロバイダー機能レシーバーを作成する

この手順は、プロジェクトにクラスを追加することから始めます。このクラスは、SPClaimProviderFeatureReceiver から基本クラスを継承します。この実装は明白です。このため、以下の例には、サンプル コード ファイルからこの部分に対応するすべてのコードをコピーしました。

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Claims;
using Microsoft.SharePoint.Diagnostics;


namespace SqlClaimsProvider
{
    public class SqlClaimsReceiver : SPClaimProviderFeatureReceiver
    {

        private void 
              ExecBaseFeatureActivated(
              Microsoft.SharePoint.SPFeatureReceiverProperties properties)
        {
            // Wrapper function for base FeatureActivated. Used because base
            // keyword can lead to unverifiable code inside lambda expression.
            base.FeatureActivated(properties);
        }

        public override string ClaimProviderAssembly
        {
            get 
            {
                return typeof(SqlClaims).Assembly.FullName;
            }
        }

        public override string ClaimProviderDescription
        {
            get 
            { 
                return "A sample provider written by Steve Peschka"; 
            }
        }

        public override string ClaimProviderDisplayName
        {
            get 
            {
                  // This is where we reuse that internal static property.
                return SqlClaims.ProviderDisplayName; 
            }
        }

        public override string ClaimProviderType
        {
            get 
            {
                return typeof(SqlClaims).FullName; 
            }
        }

        public override void FeatureActivated(
              SPFeatureReceiverProperties properties)
        {
            ExecBaseFeatureActivated(properties);
        }
    }
}

以下の点に注意する必要があります。

  • SPClaimProviderFeatureReceiver クラスの ClaimProviderAssembly プロパティと ClaimProviderType プロパティは、先ほど作成したカスタム クレーム プロバイダー クラスの型プロパティを使用しています。

  • ClaimProviderDisplayName は、クレーム プロバイダー クラスで作成した内部静的プロパティを使用します。プロパティは、クレーム機能レシーバーで再利用できるように作成しました。

  • FeatureActivated イベントは、アクティブ化プロパティの特殊な内部メソッドを呼び出します。

手順 6: アセンブリをコンパイルして、グローバル アセンブリ キャッシュに追加する

この手順は手作業の手順としています。しかし、必要であれば、ソリューション パッケージを使用することもできます。このシナリオでは、開発モードの間、1 台のサーバーですべての作業をしています。このため、ファームに配布する準備ができているときとは異なる方法で作業していることになります。

ひとまず、アセンブリに厳密な名前が付けられていることを確認して、次にそれをコンパイルします。次に、任意の方法で、アセンブリをグローバル アセンブリ キャッシュに追加します (ここではポストビルド イベントとグローバル アセンブリ キャッシュ ツール、gacutil.exe を使用しています)。これで機能を作成して、展開する準備ができました。

手順 7: クレーム プロバイダー機能を作成して、展開する

この手順では、クレーム プロバイダーに固有のことはありません。標準的な SharePoint 機能を作成して、それを展開するだけです。クレーム プロバイダー機能を作成して、展開することの基本については、この記事の範囲外です。どのようになるか確認できるように、以下の XML を feature.xml ファイルからコピーしています。

注意

機能をインストールおよびアンインストールする方法の詳細については、「フィーチャーをインストールまたはアンインストールする」を参照してください。

<Feature   Id="3E864B5C-D855-43e4-B41A-6E054C6C0352" 
           Title="Sql Claims Provider Feature" 
           Scope="Farm" 
           ReceiverAssembly="SqlClaimsProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=eaf1ba21464322ae" 
           ReceiverClass="SqlClaimsProvider.SqlClaimsReceiver" 
           xmlns="https://schemas.microsoft.com/sharepoint/" />

この feature.xml ファイルを参照しながら、Features フォルダーに SqlClaimsProvider という名前のディレクトリを作成して、機能をインストールしました。ファームを対象範囲とする機能なので、自動的にアクティブ化されます。以下は、Windows PowerShell を使って実行する場合のコマンドです。

install-spfeature -path SqlClaimsProvider

これですべての要素が配置され、クレーム プロバイダーを試行することができます。

手順 8: サイトにログインして試行する

この最後の手順で、この記事の初めに説明した Web アプリケーションを使用します。これは、Windows クレームとフォーム ベースの認証クレームをサポートします。

注意

SharePoint へのサインインの詳細については、「受信クレーム: SharePoint にサインインする」を参照してください。

クレームが適切に拡張されたか検証するために、すべてのクレームを表示する Web パーツを作成しました。クレーム拡張が実際に機能していることを示すために、スクリーン ショットを示します。

最初に、Windows 資格情報によってサイトにログオンします。以前のコードで、Windows ユーザーには自分のひいきのチームとして常に Wingtip Toys が割り当てられることに注意してください。図 1 は、Windows ユーザーに対してこれが表示される方法を示します。

図 1. Windows ユーザーのクレーム拡張

Windows ユーザーのためのクレームの拡張

図 2 は、フォーム ベース認証ユーザーの場合を示します。

図 2. フォーム ベース認証ユーザーのクレーム拡張

フォーム ベース認証のためのクレームの拡張

これで、クレーム拡張が機能していることを確認できました。パート 2 では、ユーザー選択ウィンドウでの作業と、ユーザー選択ウィンドウでの階層のサポートおよび追加について説明します。

パート 2: 階層ノードのサポートの追加

パート 1: クレームの拡張とプロバイダーの登録 では、カスタム クレーム プロバイダーを作成する方法とクレーム拡張をする方法について説明しました。パート 2 では、ユーザー選択ウィンドウ コントロールに階層を追加する簡単な方法について説明します。この過程自体は単純ですが、パート 3 では実際に使用する方法について説明します。

次に、パート 1 で作成したクラスに戻り、SPClaimProvider クラスの SupportsHierarchy プロパティと FillHierarchy メソッドについて触れます。

以下のコード スニペットのように、SharePoint に、ユーザーが階層を満たすことができることを知らせるために、true を返す SupportsHierarchy プロパティが必要になります。

public override bool SupportsHierarchy
{
      get 
      { 
            return true; 
      }
}

SupportsHierarchy プロパティを true に設定した後で、ユーザー選択ウィンドウが表示されたときに、SharePoint により FillHierarchy メソッドが呼び出されます。

階層にノードを追加するとき、表示名とノード識別子 (ID) を提供する必要があります。その目的と共に、これまでの例で使用してきたひいきのバスケットボール チームに対応付けるために、ラベル名と ID を追跡管理する、いくつかの単純なヘルパー配列を作成しました。以下がコードの例です。ここに、ひいきのチーム名の配列も示します。

// Teams that we are using.
private string[] ourTeams = new string[] { "Consolidated Messenger", "Wingtip Toys", "Tailspin Toys " };

// Keys for our People Picker hierarchy.
private string[] teamKeys = new string[] { "empUS", "empEMEA", "empASIA" };

// Labels for our nodes in the People Picker.
private string[] teamLabels = new string[] { "US Teams", "European Teams", "Asian Teams" };

キーとラベルがこれではっきりしたので、次に、ユーザー選択が表示されたときに、ノードを追加するために使用する FillHierarchy メソッドを示します。これはデモとして、説明上、示すだけで、この特定のシナリオで機能的に不可欠というわけではありません。

サイト コレクション管理者を除いて、SharePoint サイト内のほとんどあらゆるセキュリティ アイテムを準備するためにクレームを使用することができることに注意してください。サイト コレクション管理者に対する検索が行われているときには、手がかりが得られます。その場合、entityTypes 配列は、Users という 1 つのアイテムを持ちます。その他のすべての場合では、通常、entityTypes 配列には少なくとも 6 つのアイテムがあります。つまり、決して使用しないような階層を追加することを避けるために、階層を作成するとき、特殊なチェックを追加します。

protected override void FillHierarchy(Uri context, string[] entityTypes,
      string hierarchyNodeID, int numberOfLevels,
      Microsoft.SharePoint.WebControls.SPProviderHierarchyTree hierarchy)
{                        

// Ensure that People Picker is asking for the type of entity that we 
// return; site collection administrator will not return, for example.
if (!EntityTypesContain(entityTypes, SPClaimEntityTypes.FormsRole))
      return;

// Check to see whether the hierarchyNodeID is null; it is when the control 
// is first loaded, but if a user clicks on one of the nodes, it will return
// the key of the node that was clicked. This lets you build out a 
// hierarchy as a user clicks something, instead of all at once. So I 
// wrote the code for that scenario, but I am not using it in that way.  
// Which means that I could have just as easily used an 
// if (hierarchyNodeID == null) in this particular implementation, instead
// of a switch statement.
switch (hierarchyNodeID)
{
      case null:
            // When it first loads, add all our nodes.
            hierarchy.AddChild(new 
                  Microsoft.SharePoint.WebControls.SPProviderHierarchyNode(
                  SqlClaims.ProviderInternalName, 
                  teamLabels[0], 
                  teamKeys[0], 
                  true));

            hierarchy.AddChild(new
                  Microsoft.SharePoint.WebControls.SPProviderHierarchyNode(
                  SqlClaims.ProviderInternalName,
                  teamLabels[1],
                  teamKeys[1],
                  true));

            hierarchy.AddChild(new
                  Microsoft.SharePoint.WebControls.SPProviderHierarchyNode(
                  SqlClaims.ProviderInternalName,
                  teamLabels[2],
                  teamKeys[2],
                  true));
            break;
      default:
            break;
} 
}

ここでは、hierarchyNodeID が NULL であるかどうかを調べるだけです。これは、コントロールが最初に読み込まれるときは、常に、NULL となります。これが NULL の場合、左側のウィンドウのツリーにノードを追加します。このコードが実際に機能するようにするために、アセンブリを再コンパイルして、グローバル アセンブリ キャッシュに再度追加し、IISRESET を実行します。次に、サイトを表示して、ユーザー選択ウィンドウを表示し、権限の変更を試行することができます。図 3 は、このコードを実装した後のユーザー選択ウィンドウを示します。

図 3. 階層ノードが表示されるユーザー選択ウィンドウ

階層ノードが表示されるユーザー選択ウィンドウ

ここでも注意すべき点が 1 つあります。これまでの説明をよく読まれていれば、ユーザー選択ウィンドウで、クレーム プロバイダー名を、コード Basketball Teams の Name プロパティの値ではなく、[Steve's SQL Claims Provider] と表示していることに気づかれたはずです。これは、単に手順を省いたためです。この名前は、当初クレーム プロバイダーに付けた名前です。このシナリオを完成した後で、名前を変更しようとしたのですが、クレーム プロバイダー リストで更新するすべての手順を実行しませんでした。これが、名前がそうなっている理由です。

パート 3 では、カスタムクレーム プロバイダーを使用して、ユーザー選択ウィンドウでクレームを検索できるようにする方法について説明します。

パート 3: クレームの検索

この記事の最初の 2 つのパートでは、カスタムクレーム プロバイダーを作成する方法、クレーム拡張をして、プロバイダーを登録する方法、そしてユーザー選択ウィンドウに階層を追加する方法について説明しました。パート 3 では、カスタム クレーム プロバイダーのユーザー選択ウィンドウで、クレームの検索を実装する方法について説明します。カスタム クレームを選択する方法なしでは、ひいきのバスケットボール チームに基づくサイトの権限を準備できないことになります。

これは適切に理解されていないことが多い重要な点なので、まず、このことについて十分に理解してください。ユーザーの属性に基づいた権限の準備では、ユーザーがだれであるかによる場合と比較して、多くの可能性が開かれます。このシナリオでの場合のように、だれであるかは気にする必要はありません。どのようにログインしたかも気にする必要はありません。Windows ユーザーあるいはフォーム ベースの認証ユーザーであるかどうかも関係ありません。

問題は、そのユーザーのひいきのバスケットボール チームがどれかということだけです。ここに、Microsoft Office SharePoint Server 2007 からあり、SharePoint 2010 でもまだ存在する問題があります。職場では、私は Steve Peschka という Windows 資格情報を使用して、SharePoint サイトにログオンします。しかし、自宅では、エクストラネット経由でサイトを表示し、フォーム ベースの認証を使用する必要があります。

このシナリオでは、フォーム ベースの認証ユーザー、user1 であると想定します。ここでの問題は何でしょうか。SharePoint にとっては、2 人のユーザーがいることになります。SharePoint Server 2007 や SharePoint 2010 で、ユーザー マッピングのようなことをする方法はありません。"Steve Peschka という Windows ユーザーと、フォーム ベース認証ユーザー user1 は、実際には同じ人物です" と知らせることはできないわけです。

このことはもはや問題ではありません。なぜでしょうか。なぜなら、人物に基づいて権限を割り当てていないためです。その人物のひいきのバスケットボール チームに基づいて権限を割り当てているからです。ここで実装したシナリオは単純化されたものです。しかし、たとえば、人物に関連付けられた、企業のメタデータというものを想定することができます。そして、Windows 認証、フォーム ベースの認証、SAP、CRM など、その人物が使用するすべての異なる ID を確認するために、クレーム プロバイダーがその他のシステムで検索をして、いくつかのその他の識別子あるいは一連のクレームをその ID にマップすることができたとします。それらのクレームは、リソースへのアクセスを許可するために使用されます。

異なる Web アプリケーション間のシングル サインオンが必要でしょうか。繰り返しますが、Web アプリケーション 1 の user1 は、Web アプリケーション 2 の user1 とは異なります。これは問題ではありません。ひいきのバスケットボール チームのクレームを使用している限り、認証するたびに拡張をするので、その人物はこれらの Web アプリケーションの間でシームレスに移動することができます。この方法は完ぺきではありません。しかし、以前のセキュリティ モデルよりは確実に完ぺきに近いといえます。

次に、ユーザー選択ウィンドウでの検索のサポートについて説明します。カスタム クレーム プロバイダーが検索をサポートするために、SPClaimProvider クラスの以下のプロパティとメソッドのサポートを追加する必要があります。SupportsSearch、SupportsResolve、FillSearch、FillResolve (入力パラメーターとして SPClaim をオーバーロード)、FillSchema、および FillEntityTypes です。

これらのプロパティは明白ですので、以下のコードで最初に確認してください。

public override bool SupportsSearch
{
      get 
      { 
            return true; 
      }
}

public override bool SupportsResolve
{
      get 
      { 
            return true; 
      }
}

FillSearch は、おそらく最も興味深いメソッドです。以下のコードで確認してください。

protected override void FillSearch(Uri context, string[] entityTypes, 
      string searchPattern, string hierarchyNodeID, int maxCount,
      Microsoft.SharePoint.WebControls.SPProviderHierarchyTree searchTree)
{

// Ensure that People Picker is asking for the type of entity that we 
// return; site collection administrator will not return, for example.
if (!EntityTypesContain(entityTypes, SPClaimEntityTypes.FormsRole))
      return;

// The counter to track what node we are in; it will be used to call into
// our helper arrays that were covered in part 1 and part 2 of this article.
int teamNode = -1;

// NOTE: If we were not using hierarchies in the People Picker, we would
// probably use a list of PickerEntity instances so that we could
// add them all to the People Picker in one call. I have stubbed it out
// here for demonstration purposes so you can see how you 
// would do it. 
// Picker entities that we will add if we find something.
// List<PickerEntity> matches = new List<PickerEntity>();

// The node where we will place our matches.
Microsoft.SharePoint.WebControls.SPProviderHierarchyNode matchNode = null;

// Look to see whether the value that is typed in matches any of our teams.
foreach (string team in ourTeams)
{
      // Increment team node tracker.
      teamNode += 1;

      // Simple way to do a string comparison to the search criteria.
      // This way, all a person has to type in to find Consolidated Messenger is "b".
      if (team.ToLower().StartsWith(searchPattern.ToLower()))
      {
            // We have a match, create a matching entity.
            // This is a helper method that I will explain later.
            PickerEntity pe = GetPickerEntity(team);

            // If we did not have a hierarchy, we would add it here
            // by using the list described previously.
            // matches.Add(pe);

            // Add the team node where it should be displayed; 
            // ensure that we have not already added a node to the tree
            // for this team's location.
            if (!searchTree.HasChild(teamKeys[teamNode]))
            {
                  // Create the node so that we can show our match in there too.
                  matchNode = new 
                  SPProviderHierarchyNode(SqlClaims.ProviderInternalName,
                  teamLabels[teamNode],
                  teamKeys[teamNode],
                  true);

                  // Add it to the tree.
                  searchTree.AddChild(matchNode);
             }
             else
                  // Get the node for this team.
                  matchNode = searchTree.Children.Where(theNode =>
                  theNode.HierarchyNodeID == teamKeys[teamNode]).First();

            // Add the picker entity to our tree node.
            matchNode.AddEntity(pe);
      }
}

// If we were adding all the matches at once,that is, if we were not using
// a hierarchy, then we would add the list of matches here.
// if (matches.Count > 0)
//    searchTree.AddEntities(matches);
}

このコードもおそらく説明をまったく必要としません。基本的に、ここで発生したことは、ユーザーがユーザー選択ウィンドウの検索ボックスに何かを入力して、検索ボタンをクリックしたということです。SupportsSearch プロパティが true を返すため、クレーム プロバイダーが呼び出されます。呼び出されるメソッドは、FillSearch です。そのメソッドで、searchPattern 入力パラメーターによって提供される、ユーザーが入力した内容を確認します。すべてのチーム名を確認し、そのうちのどれが検索ボックスに入力された値で始めるか判定します。入力された値で始まる場合、新しい PickerEntity を作成して、そのチームの場所を含む検索ツリー階層ノードを検索あるいは作成し、そのノードに PickerEntity エンティティを追加します。

以前のコードでは、見つかったチームの名前を渡す GetPickerEntity という名前の特殊なヘルパー関数を使用しました。これは以下のコードで示されます。

private PickerEntity GetPickerEntity(string ClaimValue)
{

// Use the helper function!
PickerEntity pe = CreatePickerEntity();

// Set the claim that is associated with this match.
pe.Claim = CreateClaim(SqlClaimType, ClaimValue, SqlClaimValueType);

// Set the tooltip that is displayed when you pause over the resolved claim.
pe.Description = SqlClaims.ProviderDisplayName + ":" + ClaimValue;

// Set the text that we will display.
pe.DisplayText = ClaimValue;

// Store it here, in the hashtable **
pe.EntityData[PeopleEditorEntityDataKeys.DisplayName] = ClaimValue;

// We plug this in as a role type entity.
pe.EntityType = SPClaimEntityTypes.FormsRole;

// Flag the entry as being resolved.
pe.IsResolved = true;

// This is the first part of the description that shows
// above the matches, like Role: Forms Auth when
// you do an forms-based authentication search and find a matching role.
pe.EntityGroupName = "Favorite Team";

return pe;
}

ここでは、新しい PickerEntity オブジェクトを作成しています。コードのコメントが示すように、SPClaimProvider クラスの CreatePickerEntity メソッドは、SharePoint が提供する別のヘルパー関数です。繰り返しますが、可能な場合はヘルパー関数を使用することを強く推奨します。

PickerEntity オブジェクトを作成した後で、"それ" を記述する方法が必要になります。この場合、"それ" はひいきのバスケットボール チームのクレームです。システムにそれを示す方法は、クレーム拡張コードと同じ手法を使用して、クレームを作成することです。これが、ある人物のひいきのチームを、ここで使うひいきのチームのクレームに挿入できるように、このヘルパー関数にチーム名を渡した理由です。その後、複数のプロパティを PickerEntity オブジェクトに設定します。そうすることで、Windows クレームあるいはフォーム ベースの認証クレームで見られるその他のクレームと同じように表示され、動作します。次に、作成した PickerEntity を返します。

しかし、作業はまだ完了していません。この時点で処理を終えると、ユーザー選択ウィンドウでクレームを表示して、選択することができてしまいます。[ユーザー選択ウィンドウ] ダイアログ ボックスを閉じるために [OK] ボタンをクリックしたとき、入力コントロールにクレームが表示されます。このクレームには、解決されていないことを示す、赤の波状の下線が付いています。このクレームを、ここでは解決することはできません。

[ユーザー選択ウィンドウ] ダイアログ ボックスを閉じるために [OK] ボタンをクリックすると、実際には、SharePoint は、クレーム プロバイダーの FillResolve メソッドに別の呼び出しを試行します。これは、オーバーロードされたメソッドです。[ユーザー選択ウィンドウ] ダイアログ ボックスを閉じるときに呼び出されたメソッドは、SPClaim 入力パラメーターを含むメソッドです。次に、以下のコードで、そのメソッドの実装を確認してください。

protected override void FillResolve(Uri context, string[] entityTypes, 
      SPClaim resolveInput, 
      List<Microsoft.SharePoint.WebControls.PickerEntity> resolved)
{

// Ensure that People Picker is asking for the type of entity that we 
// return; site collection administrator will not return, for example.
if (!EntityTypesContain(entityTypes, SPClaimEntityTypes.FormsRole))
      return;

// Same sort of code as in search, to validate that we have a match.
foreach (string team in ourTeams)
{
if (team.ToLower() == resolveInput.Value.ToLower())
{
      // We have a match; create a matching entity with helper method.
      PickerEntity pe = GetPickerEntity(team);

      // Add it to the return list of picker entries.
      resolved.Add(pe);
}
}

FillResolve メソッドは明白です。この記事の「パート 1: クレームの拡張とプロバイダーの登録」で示したように、SPClaim クラスの Value プロパティには、クレームの値が含まれることを思い出してください。ユーザー選択ウィンドウで複数のアイテムが選択されていることがあるため、クレームが渡される際に、クレーム値がいずれかのチームに一致するか確認するために、チームのリスト内のアイテムを、再度、列挙します。一致がある場合は、PickerEntity オブジェクトを作成するためにヘルパー メソッドを呼び出し、SharePoint の PickerEntity インスタンスのリストにそれを追加します。これで、ユーザー選択ウィンドウで選択をした後で、入力コントロール内に解決されたエントリが表示されるようになります。

FillSchema メソッドと SPClaimProvider 基本クラスの FillEntityTypes メソッドの、2 つのメソッドをさらに実装する必要があります。FillSchema メソッドでは、ユーザー選択ウィンドウで使用する必要最小限のプロパティである、表示名を追加します。これは、スキーマに表示名を追加することによって行います。

FillEntityTypes メソッドでは、クレーム プロバイダーが使用する、1 つあるいは複数のクレームの種類を返す必要があります。今回は、クレームの種類を GetPickerEntity メソッドの SPClaimEntityTypes.FormsRole と定義していました。このため、以下のコードのように、エンティティの種類のリストにその役割を追加しました。

protected override void 
FillSchema(Microsoft.SharePoint.WebControls.SPProviderSchema schema)
{
// Add the schema element that we need at a minimum in our picker node.
schema.AddSchemaElement(new 
      SPSchemaElement(PeopleEditorEntityDataKeys.DisplayName, 
      "Display Name", SPSchemaElementType.Both));
}

protected override void FillEntityTypes(List<string> entityTypes)
{
// Return the type of entity claim that we are using (only one in this case).
entityTypes.Add(SPClaimEntityTypes.FormsRole);
}

図 4 は、wingtip を検索した後で、ユーザー選択ウィンドウがどのように表示されるかを示します。

図 4. ユーザー選択ウィンドウにおける検索

[ユーザー選択ウィンドウ] での検索

図 5 は、クレームを追加して、[OK] ボタンをクリックした後で、入力コントロールがどのように表示されるかを示します。

図 5. クレームの追加後に表示される入力コントロール

クレームの追加後に表示される入力コントロール

これで、コードの観点からは、作業は完了です。ここで、この記事の最初の説明と、これまでの作業を関連付けます。これで、ひいきのバスケットボール チームに基づいて権限を準備できるようになりました。ここでは、ひいきのチームが Wingtip Toys であるユーザーが、サイトにコンテンツを提供することができると決定したとします。この場合、[メンバー] グループにこのクレームを追加します。図 6 は、その結果を示します ([Windows Claims] サイト コレクションの名前です。混乱しないようにしてください)。

図 6. メンバー グループにクレームを追加する

メンバー グループにクレームを追加

ユーザーがだれであるか、あるいはどのようにログオンしたかは関係ないということを思い出してください。サイトでの、Windows のユーザー、Windows のグループ、フォーム ベースの認証ユーザー、あるいはフォーム ベースの認証ロール権限をいずれに対しても承認したわけではありません。Wingtip Toys に対するクレームを [メンバー] グループに追加し、Consolidated Messenger に対するクレームを [ビジター] グループに追加しただけです。

図 7 では、サイト コレクションのすべてのグループのリストがどのように表示されるかを示します。

図 7. サイト コレクションのグループ権限のリスト

サイト コレクションのグループ権限のリスト

この記事で、クレーム認証とクレーム プロバイダーがどれだけ強力かを理解いただけたはずです。この記事の最後のパートでは、入力コントロールにクレーム名を入力しようとしているユーザーのサポートを実装する方法について説明します。

パート 4: 名前解決のサポート

この記事の最初の 3 つのパートでは、エンド ツー エンドのクレーム プロバイダーの作成に必要なサポートの大部分を実装しました。この最後のパートでは、入力コントロールに名前解決サポートを実装する方法について説明します。

名前解決サポートを追加するには、SPClaimProvider クラスの SupportsResolve プロパティと FillResolve メソッドを実装する必要があります。

良い点として、すでに「パート 3: クレームの検索」で、FillResolve メソッド オーバーロードの 1 つと、SupportsResolve プロパティを実装する方法について説明しました。そのため、このセクションは簡単です。以下は、「パート 3: クレームの検索」に示さなかった FillResolve メソッドのその他のオーバーロードを実装するコードです。

protected override void FillResolve(Uri context, string[] entityTypes, 
      string resolveInput, 
      List<Microsoft.SharePoint.WebControls.PickerEntity> resolved)
{

// Ensure that People Picker is asking for the type of entity that we 
// return; site collection administrator will not return, for example.
if (!EntityTypesContain(entityTypes, SPClaimEntityTypes.FormsRole))
      return;
 
// Same sort of code as in search, to validate that we have a match.
foreach (string team in ourTeams)
{
      if (team.ToLower() == resolveInput.ToLower())
      {
            // We have a match;, create a matching entity.
            PickerEntity pe = GetPickerEntity(team);

            // Add it to the return list of picker entries.
            resolved.Add(pe);
       }
}
}

これまでの説明を読まれていれば、このコードのチャンクは明白です。よくわからない点があれば、再度「パート 3: クレームの検索」をご覧ください。

これですべてのコードについて説明しました。入力コントロールを表示して、チーム名を入力し、解決ボタンをクリックすると、以下の画像のように、入力コントロールが名前解決の前と後で表示されます。図 8 は、チーム名を入力するとき、入力コントロールがどのように表示されるかを示します。

図 8. 解決ボタンをクリックする前の入力コントロール

解決前の入力コントロール

図 9 は、解決ボタンをクリックした後の入力コントロールを示します。

図 9. 解決ボタンの後の入力コントロール

解決後の入力コントロール

これで、すべての説明は終わりです。クレーム認証プランの構築にこの情報が役立てば幸いです。

まとめ

クレームを拡張して、名前解決を提供するために SharePoint 2010 でクレーム プロバイダーを使用することができます。クレーム認証を使用して、ユーザーがだれか、あるいはユーザーがどのように認証されるかを知る必要もなく、クレームに基づいて権限を割り当てることができます。知る必要があるのはユーザーの属性のみです。たとえば、ある人物に関連する企業のメタデータを使用して、Windows 認証、フォーム ベースの認証、SAP、CRM など、その特定の人物が使用するすべての異なる ID を見つけるために、その他のシステムに対してクレーム プロバイダーが検索をし、いくつかのその他の識別子あるいは一連のクレームをその ID にマップすることができたとします。それらのクレームは、リソースへのアクセスを許可するために使用されます。

その他の技術情報

詳細については、次のリソースを参照してください。