次の方法で共有


Geneva Framework

カスタム セキュリティ トークン サービスを構築する

Michele Leroux Bustamante

この記事は、"Geneva" Framework のプレリリース版に基づいて書かれています。ここに記載されているすべての情報は、変更される場合があります。

この記事では、次の内容について説明します。

  • Geneva Framework を使用してセキュリティ トークン サービスを実装する
  • フェデレーション セキュリティ
  • クレームの変換
この記事では、次のテクノロジを使用しています。
Windows Communication Foundation、ASP.NET、Geneva Framework

コードは MSDN コード ギャラリーからダウンロードできます。
オンラインでのコードの参照

目次

セキュリティ トークン サービス入門
カスタムのアクティブ STS を構築する
SecurityTokenService を拡張する
STS をホストして構成する
セキュリティ トークン ハンドラ
カスタムのパッシブ STS を構築する
FederatedPassiveTokenService コントロール
SessionAuthenticationModule
ユーザー認証
クレームの変換
まとめ

Microsoft のクレームベース アクセス (CBA) プラットフォーム戦略 (コードネーム "Geneva") には、"Geneva" Framework、"Geneva" Server、および Windows CardSpace "Geneva" が組み込まれています。Geneva Framework は、セキュリティ トークン サービス (STS) によって発行されたトークンを使用するクレームベース アプリケーションおよびサービスを構築するためのツールに加えて、カスタム STS や、Windows CardSpace 対応のアプリケーションを構築するためのツールを開発者に提供します。Geneva Server はエンタープライズ STS ですが、Geneva Framework を使用すると、エンタープライズ レベルの機能が不要な環境に合わせてカスタム STS を構築できます。Windows CardSpace Geneva は、Windows クライアント コンピュータ上で ID セレクタおよび ID プロバイダとして機能する Windows CardSpace の進化版です。

Geneva Framework を取り上げた前回の記事では、STS によって発行されたトークンを使用する、クレームベースの Windows Communication Foundation (WCF) サービスを構築するためのより優れた方法について説明しました。今回は、Geneva Framework を使用してカスタム STS を構築します。

この記事を読み進める前に、Keith Brown および Sesha Mani が開発者に向けて執筆した「Geneva Framework ホワイト ペーパー」と、筆者の前回の記事「クレームベースの WCF サービスを構築するためのより優れたアプローチ」をお読みください。

セキュリティ トークン サービス入門

STS の最も重要な役割は、呼び出し元を認証するセキュリティ ゲートウェイとして機能することと、呼び出し先を表すクレームを保持するセキュリティ トークンを発行することです。これは、Geneva Server をベースとする STS と Geneva Framework を使用して構築された STS のいずれにも当てはまります。紹介した記事にあるように、STS 認証によって実現できるシナリオは複数存在します。

  • アプリケーションとサービスを認証メカニズムから切り離すことにより、それらのアプリケーションとサービスが適切なクレームの承認に専念できるようにする。
  • アプリケーションとサービスの実装を複雑化することなく、複数の資格情報の種類をサポートする。
  • 各ドメインの STS 間で信頼関係を確立することにより、フェデレーション シナリオ (ユーザーを各自のドメインで認証すると共に、そのユーザーに対して別のドメイン内のリソースへのアクセス許可を与える) をサポートする。
  • 認証されたユーザーにダウンストリーム サービスへのアクセス許可を与える ID 委任シナリオをサポートする。
  • クレームの変換を容易にすることで、アプリケーションとサービスで適切なクレームを承認に使用できるようにする。

これらのシナリオは、いずれもパッシブ フェデレーション (ブラウザベース) またはアクティブ フェデレーション (Windows クライアントベース) に基づいて実現できます。次に、これらのシナリオを詳しく見ていくと共に、関係するロジックを Geneva Framework を使用して構築したカスタム STS に組み込む方法を説明します。

STS の実装に踏み込む前に、まずいくつかの基本的な事項を見直しましょう。アクティブ フェデレーションで使用される STS は、WS-Federation のアクティブな要求側プロファイル (「WS-Federation TC」を参照) と、(主に) WS-Trust 仕様 (「WS-Trust 1.3」を参照) を実装したものです。

大まかに言うと、WS-Trust では 4 つのサービス操作 (Issue、Validate、Renew、および Cancel) とのコントラクトが定義されています。これらの操作は、それぞれ、セキュリティ トークンの要求、セキュリティ トークンの検証、有効期限の切れたセキュリティ トークンの更新、使用されなくなったセキュリティ トークンの取り消しのために、クライアントから呼び出されます。各操作は、WS-Trust 仕様に準拠した RST (Request for Security Token) 形式の送信メッセージと RSTR (RST Response) 形式の返信メッセージの形をとります。この記事の内容は、発行されるトークンが Security Assertion Markup Language (SAML) 1.1 トークンまたは SAML 2.0 トークンであることを前提にしています。

図 1 に、アクティブにトークンを発行する場合の RST および RSTR の主なコンテンツを示します。RST メッセージには、発行するトークンの種類 (ここでは SAML)、証明書利用者 (RP) が要求したクレーム (発行されたトークンに保持される)、"AppliesTo" で示される RP に関する情報 (URL のほか、RP を識別するための資格情報が一般的)、RSTR で返される "所有の証明" キー (証明キー) に使用されるキー マテリアル (オプションです。図には示されていません) など、セキュリティ トークンを要求するときに必要な情報が含まれています。

fig01.gif

図 1 アクティブ フェデレーション シナリオでのトークンの発行

トークンの発行に成功した場合、RSTR には発行された SAML トークンと証明キーが含まれます (ただし、STS が使用する証明キーを決定し、その証明キーを RSTR で返すことになっている場合)。SAML トークンには認証されたパーティに対する適切なクレームが追加され、改ざんを防ぐために STS によって署名されます。また、このトークンには RP に対して暗号化された証明キーが含まれます。さらに、目的の受信者だけが処理できるようにトークン自体も RP に対して暗号化されます。

クライアントは証明キーを使用して RP に対するメッセージに署名します。RP は、SAML トークン内の証明キーの暗号化を解除できるか、メッセージを拒否できる必要があります。トークン内の証明キーがメッセージ上の署名と一致した場合、RP の呼び出しを送信したのがトークンを要求したパーティであることが証明されます。

パッシブ フェデレーションのシナリオは、WS-Federation のパッシブな要求側プロファイルに基づくものです。このシナリオではブラウザベースの通信が行われます。ベースのメッセージングはやはり WS-Trust に準拠していますが、RST は STS URL でクエリ文字列パラメータに分割され、RSTR は通常はフォーム パラメータとして RP にポストされます。パッシブ STS および RP は、これらのパラメータをフェデレーション Web ハンドラを使用してインターセプトします。パッシブ STS では、WS-Trust 要求を直接処理することも、基になっている WS-Trust の実装に渡すこともできます。図 2 は、パッシブ フェデレーション シナリオにおける RST と RSTR の処理方法を示しています。

fig02.gif

図 2 パッシブ フェデレーション シナリオでのトークンの発行

アクティブ フェデレーション シナリオとパッシブ フェデレーション シナリオにおける重要な違いの 1 つは、発行される SAML トークンの種類です。通常、アクティブ フェデレーションでは、"holder-of-key" タイプのサブジェクト確認が行われる SAML トークンが発行されます。つまり、前に説明したように、認証のためにトークンを送信しているクライアントがトークンを要求したサブジェクトである (これは ActAs 動作とも呼ばれる) ことを証明するために使用される証明キーがトークンに含まれます。パッシブ フェデレーション シナリオでは、通常、"bearer" タイプのサブジェクト確認が行われる SAML トークン (bearer トークンとも呼ばれる) が発行されます。このタイプのトークンには証明キーが含まれないので、キーのないトークンと呼ばれることもあります。このシナリオでは、トークンを安全な方法で STS から入手して RP に転送するために、トランスポートが使用されます。

これらの概念 (WS-Federation、WS-Trust、および SAML トークン) は、この後で説明する内容の重要な背景情報です。まず、Geneva Framework を使用してアクティブ STS を構築する方法について説明します。その次にパッシブ STS の構築方法を示し、最後に各 STS を応用したシナリオをいくつか紹介します。

カスタムのアクティブ STS を構築する

図 3 のような単純なアクティブ フェデレーション シナリオでは、通常は次の 3 つの要素が関係します。

  • RP。クライアントによって呼び出されるサービスです。
  • WS-Trust プロトコルをサポートしている単一の STS。STS もサービスとして実装されます。この STS は、呼び出し元を認証し、呼び出し元を示すクレームを含むセキュリティ トークンを発行します。ID プロバイダまたは IP-STS とも呼ばれます。
  • クライアント。ここでは Windows ベースのアプリケーションです。クライアントは STS で認証を行い、その結果発行されたトークンを取得します。さらに、RP にメッセージを送信して、認証と承認のためにトークンを提供します。これらの処理はプロキシを介して行われます。

fig03a.gif

図 3 単一の RP とアクティブ IP-STS が関与する単純なフェデレーション シナリオ

図 4 に、この実装の背後にある可動部分を示します。ここには、SecurityTokenService のカスタム実装が含まれています。また、フェデレーション用にランタイムを初期化するために ServiceHost の拡張機能 (WSTrustServiceHost) が使用され、WSTrustContract 型の派生クラスを使用して 1 つ以上の WS-Trust エンドポイントが構成されています。ID モデル ランタイムのその他の構成設定も行われています。ここからは、Geneva Framework ベースのカスタム STS の実装におけるこれらの要素について、個別に見ていきます。

fig04.gif

図 4 カスタムのアクティブ STS およびアクティブ IP-STS の実装アーキテクチャ

SecurityTokenService を拡張する

Geneva Framework は、Microsoft.IdentityModel.SecurityTokenService 名前空間の SecurityTokenService 型を通じてカスタム STS を構築するための中心的な機能を提供します。この抽象クラスは、非常に複雑な処理 (RST メッセージと RSTR メッセージの処理、およびセキュリティ トークンの生成) を行います。カスタム STS 型はこのクラスを継承し、(少なくとも) 次の機能を提供します。

  • カスタムの SecurityTokenServiceConfiguration インスタンスを受け取って STS のいくつかの基本的な機能を構成するコンストラクタ (後述します)。
  • 要求の対象の RP を検証し、その RP に適切な暗号化資格情報を、またセキュリティ トークンに署名資格情報を提供する GetScope のオーバーライド。
  • 作成されるセキュリティ トークンにクレームを提供する GetOutputClaimsIdentity のオーバーライド。

図 5 に、この機能を含む単純なカスタム STS の実装のコードを示します。図 1図 2 に示したアクティブ STS の通信のフローを思い出してください。STS の実装である IdentitySTS は、GetScope が呼び出されたときに受信 RST を検証します。具体的には、RST の AppliesTo 要素が信頼された URI を実際に示しているかどうかを確認します。STS は、トークンの発行対象として適切な、信頼された一連の RP と、その証明書を管理するものと考えられます。GetScope は、AppliesTo が検証にパスした場合、スコープの EncryptingCredentials プロパティを適切な証明書に設定します。この場合は "RPKey" です。さらに、SigningCredentials プロパティは、発行されたトークンに署名するために使用される適切な証明書に設定されます。これは通常は STS のプライベート キーであり、この場合は "IPKey" です。

図 5 単純なカスタム STS の実装

public class IdentitySTS : SecurityTokenService
{
    public IdentitySTS(SecurityTokenServiceConfiguration config)
        : base( config )
    {
    }

    protected override IClaimsIdentity GetOutputClaimsIdentity(
        IClaimsPrincipal principal, RequestSecurityToken request, 
        Scope scope)
    {
        IClaimsIdentity claimsIdentity = new ClaimsIdentity();

        claimsIdentity.Claims.Add(new Claim(ClaimTypes.Name, 
            principal.Identity.Name));
        claimsIdentity.Claims.Add(new Claim(ClaimTypes.Role, "Users"));

        return claimsIdentity;
    }

    protected override Scope  GetScope(
        Microsoft.IdentityModel.Claims.IClaimsPrincipal principal, 
        RequestSecurityToken request)
    {

        Scope scope = new Scope(request);
        scope.EncryptingCredentials = this.GetCredentialsForAppliesTo(
                                                     request.AppliesTo);
        scope.SigningCredentials = new 
          X509SigningCredentials(CertificateUtil.GetCertificate(StoreName.My, 
          StoreLocation.LocalMachine, "CN=IPKey"));
        return scope;
    }

    private X509EncryptingCredentials GetCredentialsForAppliesTo(Endpoint
        Address appliesTo)
    {
        if (appliesTo == null || appliesTo.Uri ==null || 
          string.IsNullOrEmpty(appliesTo.Uri.AbsolutePath))
        {
            throw new InvalidRequestException(
                "AppliesTo must be supplied in the RST.");
        }

        X509EncryptingCredentials creds = null;
        if (appliesTo.Uri.AbsoluteUri.StartsWith(
            "http://localhost:8000/RelyingPartyService"))
        {
            creds = new X509EncryptingCredentials(
                CertificateUtil.GetCertificate(StoreName.TrustedPeople, 
                StoreLocation.LocalMachine, 
                "CN=RPKey"));
        }
        else
            throw new InvalidRequestException(String.Format(
                "Invalid relying party address: {0}", 
                appliesTo.Uri.AbsoluteUri));

        return creds;
    }
}

GetOutputClaimsIdentity が呼び出されると、認証された呼び出し元の ID を持つ ClaimsPrincipal がランタイムによって渡されます。通常、この ID は、呼び出し元に付与する適切なクレームを特定するために使用されます。図 5 のコードでは、呼び出し元に対して名前クレームとハードコードされたロール クレームを生成し、それを ClaimsIdentity の形で返しています。この ClaimsIdentity がランタイムにクレームを提供することにより、トークンを発行できるようになります。

この STS の実装も次の機能で拡張できます。

  • GetOutputClaimsIdentity にカスタム資格情報ストアでユーザーを検索するためのコードを追加し、他のクレームを検索できます。たとえば、一連のロール、ユーザーについてのその他の関連情報 (電子メール アドレスなど)、より細かいアプリケーション権限 (作成、読み取り、更新、削除など) を表すカスタム クレームなどです。
  • GetScope では、信頼されたすべての RP とそれに関連付けられている証明書が登録されているカスタム データベースで AppliesTo URI を検索できます。

STS をホストして構成する

WCF に詳しい読者なら、クライアントがサービスにメッセージを送信できるようにするためには、1 つ以上のエンドポイントを構成する必要があることをご存知でしょう。STS の場合、各エンドポイントで使用されるサービス コントラクトは、Issue、Validate、Renew、Cancel という 4 つの操作が定義されている WS-Trust プロトコルに準拠している必要があります。STS で実装できる WS-Trust プロトコルのバージョンは、実際には 2 つあります。

  • WS-Trust 1.3: WS-Trust 仕様の最新バージョンです。
  • WS-Trust February 2005: 数多くの業界パートナーが標準化を待っている間に実装したバージョンです。

SecurityTokenService 型の数あるメソッドの中で、特に GetScope() と GetOutputClaimsIdentity() の非同期実装を提供することもできます。これによってスケーラビリティが高まり、証明書へのアクセスやクレーム データの操作など、大量の I/O が発生する操作への対応が可能になります。STS のエンドポイントを構成する際には、そのエンドポイントで公開するコントラクトを選択する必要があります。Microsoft.IdentityModel.Protocols 名前空間には、STS のエンドポイント向けの 2 つのサービス コントラクト (IWSTrust13SyncContract と IWSTrustFeb2005SyncContract) が含まれています。図 6 に、2 つのエンドポイントのある STS サービスの構成を示します。これらのエンドポイントで、各コントラクトが公開されています。ただし、非同期バージョンのコントラクトも存在することに注意してください。こうしたコントラクト (IWSTrust13AsyncContract と IWSTrustFeb2005AsyncContract) は、非同期プロキシを実装するために使用されます。

図 6 複数の WS-Trust エンドポイントがある STS サービスの構成

<service name=
  "Microsoft.IdentityModel.Protocols.WSTrust.WSTrustServiceContract" 
  behaviorConfiguration="stsBehavior">
  <endpoint address="WSTrustFeb05" binding="wsHttpBinding" 
    contract="Microsoft.IdentityModel.Protocols.WSTrust.
    IWSTrustFeb2005SyncContract"/>
  <endpoint address="WSTrust13" binding="wsHttpBinding"  
    contract="Microsoft.IdentityModel.Protocols.WSTrust.
    IWSTrust13SyncContract"/>
</service>

STS は、以前からあるクライアントとの下位互換性を維持するために、WS-Trust February 2005 に基づくエンドポイントを公開する必要があります。両方のコントラクトを実装するサービス型は、Microsoft.IdentityModel.Protocols.WSTrust 名前空間内の WSTrustServiceContract 型です。この型は、STS の <service> 構成セクションで参照される必要があります。

図 4 のダイアグラムに示したように、<service> 構成とそのエンドポイントは、適切な WSTrustServiceContract 型でホストを初期化するために使用されます。この型も、ホストの初期化中に SecurityTokenService のカスタム実装への参照で初期化されます。これが、ランタイムがメッセージをカスタム STS に送信するときのしくみです。

図 6 の場合、両方の STS エンドポイントが Windows 資格情報を使用して呼び出し元を認証します (wsHttpBinding の既定の動作)。STS は、異なるバインドが構成された複数のエンドポイントを公開することで、種類の異なる資格情報をサポートできます。この場合は、資格情報の種類ごとに適切なセキュリティ トークン ハンドラを構成する必要もあります。トークン ハンドラの構成設定については、後ほど簡単に説明します。

Geneva Framework は、カスタム ServiceHost 型である WSTrustServiceHost を提供します。これは、STS インスタンスをホストするために使用されます。次のコードは、自己ホスト環境で WSTrustServiceHost 型を構築する方法を示しています。

WSTrustServiceHost stsHost = 
  new WSTrustServiceHost(new IdentitySTSConfiguration());
stsHost.Open();

WSTrustServiceHost は、カスタム SecurityTokenServiceConfiguration インスタンスを使用して WS-Trust エンドポイントでランタイムを初期化し、STS のメタデータ交換動作を有効にし、メタデータ交換エンドポイントを構成します。

STS が IIS にホストされている場合は、同じ結果を得るために WSTrustServiceHostFactory 型が使用されます。.svc ファイルでは、次のように、@ServiceHost の構成でファクトリ型とカスタムの SecurityTokenServiceConfiguration 型を指定します。

<%@ ServiceHost Factory="Microsoft.IdentityModel.Protocols.WSTrust. 
  WSTrustServiceHostFactory" 
  Service="STS.IdentitySTSConfiguration"  %>

ファクトリは、指定された構成で起動時に WSTrustServiceHost を初期化します。

STS の WSTrustServiceHost を初期化するには、カスタムの SecurityTokenServiceConfiguration 型が必要です。図 7 に、IdentitySTSConfiguration というカスタム実装を示します。

図 7 カスタムの SecurityTokenServiceConfiguration

public class IdentitySTSConfiguration: SecurityTokenServiceConfiguration
{

    public IdentitySTSConfiguration(): base("http://localhost:8010/sts")
    {

      this.TokenIssuerName = "http://localhost:8010/sts";

      this.SigningCredentials = new 
        X509SigningCredentials(CertificateUtil.GetCertificate(StoreName.My, 
        StoreLocation.LocalMachine, "CN=IPKey"));

      this.SecurityTokenService = typeof( IdentitySTS);

    }

}

この型では、STS の URI、署名資格情報、構成が関連付けられている STS 型への参照を指定する必要があります。また、Windows CardSpace がマネージ カードをインポートできるように、STS によるマネージ カードの発行イベントで有効な URL が使用される必要があります。基本型には TokenIssuerName のコンストラクタに渡される文字列値が必要ですが、その値をコードでオーバーライドすることをお勧めします。こうすることで、コンストラクタに渡されるこの値をハードコーディングする代わりに、URI を構成から動的に設定することができます。

SecurityTokenServiceConfiguration 型は、キー サイズとトークンの種類の既定値の設定、メタデータへのアクセスの無効化、トークンの有効期間とクロック スキューの制御、カスタムの RST シリアライザおよび RSTR シリアライザの設定、呼び出し元を認証するトークン ハンドラの構成、WS-Trust エンドポイントの構成などに使用できるプロパティも公開します。

次の例は、メタデータへのアクセスの無効化と WS-Trust エンドポイント (図 6 に示したようなエンドポイント) の初期化を、<service> 構成設定を使用せずにプログラムで行う方法を示しています。

IdentitySTSConfiguration config = new IdentitySTSConfiguration();
config.DisableWsdl = true;
config.TrustEndpoints.Add(new 
  ServiceHostEndpointConfiguration("WSTrustFeb05", new WSHttpBinding(),  
  typeof(IWSTrustFeb2005SyncContract)));
config.TrustEndpoints.Add(new ServiceHostEndpointConfiguration(
  "WSTrust13", new WSHttpBinding(), 
  typeof(IWSTrust13SyncContract)));

WSTrustServiceHost stsHost = new WSTrustServiceHost(config);

基本の SecurityTokenServiceConfiguration 型は、<microsoft.identityModel> 構成セクションも読み取り、関連の STS 構成設定を初期化します。宣言によって構成できるカスタム STS の設定には、最大クロック スキュー、認証と発行のためのセキュリティ トークン ハンドラ、クレームの認証マネージャ、発行者名レジストリ、トークン リゾルバなどがあります。図 8 に、STS の便利な設定の一部を示します。

図 8 STS の <microsoft.identityModel> の構成

<microsoft.identityModel>
  <maximumClockSkew value="00:05:00"/>
  <claimsAuthenticationManager type="STS.
    CustomClaimsAuthenticationManager, STS"/>
  <securityTokenHandlers>
    <remove type="Microsoft.IdentityModel.Tokens.
      WindowsUserNameSecurityTokenHandler, 
      Microsoft.IdentityModel, Version=0.5.1.0, Culture=neutral, 
      PublicKeyToken=31bf3856ad364e35" />
    <add type="Microsoft.IdentityModel.Tokens.
      MembershipUserNameSecurityTokenHandler, 
      Microsoft.IdentityModel, Version=0.5.1.0, Culture=neutral, 
      PublicKeyToken=31bf3856ad364e35">
        <usernameSecurityTokenHandlerRequirement 
          membershipProvider="CustomProviders.CustomMembershipProvider, 
          CustomProviders, Version=1.0.0.0, Culture=neutral,
           PublicKeyToken=c03h5a64f15d0b3f" />
    </add>
  </securityTokenHandlers>
</microsoft.identityModel>

カスタムの ClaimsAuthenticationManager 型は非 Windows 資格情報に対して呼び出されます。これにより、GetOutputClaimsIdentity でクレームを発行する前にカスタムの ClaimsPrincipal 型をランタイムに提供できるようになります。カスタム セキュリティ トークン ハンドラは、特定のハンドラの既定の動作をオーバーライドする設定を提供するか、特定の資格情報用のセキュリティ トークン ハンドラを変更するように構成できます。

セキュリティ トークン ハンドラ

おそらく皆さんは、サービス動作構成によって STS エンドポイントごとの認証と承認の方法が決まると考えておられるでしょう。ここで、前回の記事を思い出してください。Geneva Framework では処理の方法が少し異なります。認証の場合、受信要求の認証に使用できる SecurityTokenHandler 型を <securityTokenHandlers> コレクションで指定します。

このコレクションには、SecurityTokenHandler 型ごとにエントリを 1 つだけ含めることができます。たとえば、KerberosSecurityTokenHandler、UserNameSecurityTokenHandler、X509SecurityTokenHandler、Saml11SecurityTokenHandler、または Saml2SecurityTokenHandler を 1 つだけ登録して、それぞれに対応する資格情報の要求を処理できます。STS エンドポイントが UserName 資格情報を予期している場合は、登録される既定の UserNameSecurityTokenHandler は WindowsUserNameSecurityTokenHandler です。図 8 では、WindowsUserNameSecurityTokenHandler を削除し、代わりに MembershipUserNameSecurityTokenHandler を追加しています。図にはメンバシップ プロバイダの関連の構成設定も示されています。

カスタムの SecurityTokenHandler 型を作成することも可能です。それらがトークンのカテゴリ (UserNameSecurityTokenHandler など) と一致する適切な基本クラスから派生している場合に限り、既定のハンドラを新しいカスタム ハンドラに置き換えることができることを覚えておいてください。図 9 に、UserNameSecurityTokenHandler のカスタム実装 (CustomUserNameSecurityTokenHandler) を示します。

図 9 カスタムの UserNameSecurityTokenHandler

public class CustomUserNameSecurityTokenHandler:   
  UserNameSecurityTokenHandler
{
  public override ClaimsIdentityCollection ValidateToken(SecurityToken token)
  {
    UserNameSecurityToken userNameToken = token as UserNameSecurityToken;
    AuthenticateUser(userNameToken.UserName, userNameToken.Password);

    return new ClaimsIdentityCollection(new IClaimsIdentity[] {
      new ClaimsIdentity(
        new Claim(System.IdentityModel.Claims.ClaimTypes.Name,
         userNameToken.UserName), "CustomUserNameSecurityTokenHandler")});
  }

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

SecurityTokenHandler のカスタム実装では、少なくとも ValidateToken と CanValidateToken をオーバーライドする必要があります。また、ValidateToken 内部で、適切な資格情報ストアに対して認証を行ってください。その認証の結果は、要求スレッドの ClaimsPrincipal にアタッチされるランタイムに返すことができるクレームのセットです。

fig10.gif

図 10 単一の RP とパッシブ IP-STS が関与する単純なフェデレーション シナリオ

CanValidateToken をオーバーライドし、True を返すことも非常に重要です。このオーバーライドを行わないと、トークン ハンドラがコレクションに登録されず、呼び出されません。

カスタムのパッシブ STS を構築する

単純なパッシブ フェデレーション シナリオには図 3 に示したアクティブ フェデレーション シナリオと同じ要素が関与しますが、違いもいくつかあります。たとえば、クライアントはブラウザであり、RP は Web アプリケーションです。IP-STS についても、HTTP ベースの通信を処理するために Web アプリケーションが前面に配置されています。図 10 に、パッシブ フェデレーションの関係要素と通信のフローを示します。

このシナリオ背後の可動部分は、中核の STS に関して言えば図 4 に示したものと似ていますが、パッシブ STS による認証の処理方法と、基になる STS 機能の呼び出し方法にいくつか明確な違いがあります。図 10 のダイアグラムには、これらの違いが大まかに示されています。パッシブ STS は、SSL 暗号化を使用してトークンの発行プロセスをセキュリティ保護する必要のある Web サイトとして実装されます。既定のページ (Default.aspx) には、基になるカスタム STS (アクティブ STS と同様に構成される) との通信を円滑に行えるようにするコントロールがホストされます。

STS サイトは、トークンの発行前に呼び出し元を認証する必要があります。このとき認証と承認に役立つのが、従来の ASP.NET の構成です。図 11 では、STS アプリケーションはフォーム認証向けに構成されているため、FormsAuthenticationModule で認証されなかった要求はログイン ページ (Login.aspx) にリダイレクトされています。

パッシブ STS は同じ基本的な STS の実装をアクティブ STS として共有できます。ただし、わずかに異なる点があります。パッシブ STS の場合、GetScope のオーバーライド (図 5 を参照) で ReplyToAddress プロパティを設定し、トークンの発行後に STS がユーザーをリダイレクトできるようにする必要があるのです。通常、このプロパティは、RST で提供される AppliesTo アドレスに基づいて、RP の既定のページに設定されます。

Scope scope = new Scope(request);
scope.ReplyToAddress = scope.AppliesToAddress + "/default.aspx";
// other scope settings

fig11.gif

図 11 フォーム認証を使用するパッシブ STS の実装アーキテクチャ

Geneva Framework の構成は、パッシブ STS の場合もアクティブ STS と同じです。SecurityTokenServiceConfiguration 型が STS を初期化するために使用され (図 7 を参照)、<microsoft.identityModel> 構成セクションの関連の設定も考慮されます。

FederatedPassiveTokenService コントロール

Geneva Framework は、パッシブ STS の必要機能を実装したコントロールを提供します。このコントロールは、サインインおよびサインアウトの HTTP 要求を処理し、各要求を RST に変換して、基になる STS の実装を呼び出します。また、RSTR 応答と RP へのリダイレクトを処理し、認証された呼び出し元のセッション cookie を書き込みます。

このコントロールをパッシブ STS サイトの既定のページに配置し、その Service プロパティを次のように SecurityTokenServiceConfiguration のカスタム実装に設定してください。

<idfx:FederatedPassiveTokenService ID="FederatedPassiveTokenService1" 
  runat="server" Service="STS.IdentityProviderSTSConfiguration, STS">
</idfx:FederatedPassiveTokenService>

このコントロールは、ユーザーが認証されていることを PreRender イベントで確認します。ユーザーは必ず認証されている必要があります。ここでは、ユーザーがこの既定のページに到達する前に認証用ページにリダイレクトされるように、STS サイトが適切に構成されていることを想定しています。

認証されたユーザーが常にこの既定のページに移動するのであれば、要求を処理するために他の構成を行う必要はありません。このコントロールは、例外を処理し、サインインおよびサインアウト要求をフックするための Error、PreSignInRequested、PostSignInRequested、PreSignOutRequested、および PostSignOutRequested イベントを提供します。

SessionAuthenticationModule

FederatedPassiveTokenService コントロールを使用する代わりに、パッシブ STS の機能をプログラムで有効にすることもできます。それにはまず、<microsoft.identityModel> 構成セクションでフェデレーション認証を有効にします。

<microsoft.identityModel>
  <federatedAuthentication enabled="true"/>
</microsoft.identityModel>

次に、パッシブ STS のフェデレーション モジュール (Microsoft.IdentityModel.Web 名前空間の SessionAuthenticationModule) を有効にします。

<modules>
  <add name="SessionAuthentication" 
    type="Microsoft.IdentityModel.Web.SessionAuthenticationModule,
    Microsoft.IdentityModel, Version=0.5.1.0,
    Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</modules>

これで、STS Web サイト内のページに送信された要求が FederatedPassiveTokenService コントロールを使用した場合と同じように処理されるにようになりました。このモジュールは、認証されていない呼び出し元をログイン ページにリダイレクトします。ログインに成功すると、呼び出し元は最初に要求した STS ページにリダイレクトされます。このようなプログラムによるアプローチにより、開発者は FederatedPassiveTokenService コントロールを使用した場合よりも処理をより細かく制御できるようになります。たとえば、このモジュールは、初期化、セキュリティ トークンの管理、サインイン、サインアウトを処理するためのさまざまなイベント (ConfigurationLoading、ConfigurationLoaded、SecurityTokenReceived、SecurityTokenValidated、SessionSecurityTokenCreated、SessionSecurityTokenReceived、SignedIn、SigningOut、SignedOut、SignInError、および SignOutError) を公開します。

ユーザー認証

STS サイトは、サポートされている資格情報の種類に応じてユーザーを認証する役割を担います。WCF を使用して実装されたアクティブ STS の場合、異なる認証メカニズムをサポートするために複数のエンドポイントを簡単に構成できますが、パッシブ STS の場合は、ASP.NET Web サイトの構成の性質上、サポート可能な認証メカニズムは 1 つだけです。したがって、サポートする認証メカニズムごとに異なるパッシブ STS サイトを用意する必要があります。もちろん、これらのサイトは同じ基本的な STS の実装を共有できます。

パッシブ STS の認証方法は、ASP.NET の構成手法に基づきます。一般的な認証方法は、Windows 認証、フォーム認証、および Windows CardSpace 認証です。Windows 認証の場合は、次の構成を使用します。

<authentication mode="Windows"/>
<authorization>
  <deny users="?"/>
</authorization>

この場合、ユーザーは対話型ダイアログを通じて認証された後に STS の既定のページにリダイレクトされるため、カスタム ログイン ページは不要です。

図 11 に示した例では、フォーム認証が使用されています。FormsAuthenticationModule は、認証されていない呼び出しを、ユーザーによる資格情報の入力が可能なログイン ページにリダイレクトします。認証後、呼び出しはログイン ページから既定の STS ページにリダイレクトされます。このページで、フェデレーション コントロールが元の要求を処理します。この場合の ASP.NET の構成は次のようになります。

<authentication mode="Forms"/>
<authorization>
  <deny users="?"/>
</authorization>

Windows CardSpace 認証の場合、STS サイトはフォーム認証向けに構成できますが、ログイン ページには Windows CardSpace 認証用の InformationCard コントロールが必要です。

クレームの変換

クレームの変換は、フェデレーション セキュリティを確保するうえで不可欠な処理であり、フェデレーションのフローのさまざまなポイントで行うことができます。IP-STS と RP が同じドメインに属している単純なフェデレーション シナリオの場合、ユーザーが認証中に提供する ID クレームの初期セットを PR が呼び出しの承認に使用できるクレームに変換するのは、IP-STS です。ユーザーは、サポートされている任意の種類の資格情報を提供して、IP-STS で認証を行うことができます。その際、資格情報を表すクレームのセットに対して評価が行われます。

IP-STS は、これらのクレームを、RP が呼び出しを承認するために使用する正規化されたアプリケーション クレームのセットに変換します。これらは、ロールやより細かいクレーム (作成、読み取り、更新、削除権限など) になります。図 12 のダイアグラムに示したシナリオでは、管理者ユーザーはログイン後、Role クレームと複数の Action クレーム (Create、Read、Update、Delete など) を付与されています。

fig12.gif

図 12 IP-STS でのクレームの変換

この種類のクレームの変換は、STS での認証の結果、ユーザーに付与されるすべてのクレームを保持するトークンが発行されるという点で便利です。ただし、これ以外の方法でクレームの変換を行わなければならない場合もあります。たとえば、発行されるクレームを現在の呼び出しコンテキストに関係するクレームに限定する、クレームのプライバシーを保護する、ドメインをまたがるフェデレーションを容易にする、などの目的がある場合です。

認証された呼び出し元に対し、RP が公開しているすべての機能に対応する数多くのクレームを付与するのは、必ずしも適切だとは言えません。クレームの数が非常に多くなるだけでなく、付与されるクレームが呼び出しコンテキストに依存してしまい、そのコンテキストがなければクレームが発行されなくなるおそれがあるのです。たとえば、ユーザーが顧客からの注文を操作する場合は、Delete クレームだけが付与されますが、そのユーザーが顧客レコードを直接操作する場合は、その権限は付与されません。

このようなケースでは、呼び出し元を特定するために IP-STS から少数のクレームを要求し、その後で呼び出しのコンテキストに対応した追加のクレーム セットを含む新しいトークンを要求するのが、RP に対して適切な処理です。たとえば、ユーザーが RP サービスで DeleteCustomer 操作を呼び出している場合、その操作へのアクセスを承認する前に、RP は RP-STS を呼び出して IP-STS からのトークンを渡し、DeleteCustomer 操作のコンテキストで Delete クレームを要求します。クレームが提供されると、呼び出しが承認されます。図 13 のダイアグラムにこの例を示します。

また、STS が発行したクレームを RP と直接共有してはならないケースもあります。たとえば、RP でユーザーの年齢を把握するために Age クレームを発行する代わりに、RP から IsOver13 クレームを要求すると、呼び出し元が RP の機能を利用できる年齢に達していることを確認できます。この場合、Age クレームの実際の値は STS から送信されません。もちろんこれは、個人の詳細情報を共有することなく RP に必要なデータを渡すことのできるクレームを ST から提供するためのテクニックです。

fig13.gif

図 13 RP-STS でのクレームの変換

あるドメインに属しているユーザーが別のドメインの RP へのアクセス許可を与えられているようなフェデレーション シナリオでも、クレームの変換は行われます。この場合は、2 つの STS、つまりユーザー ドメインの IP-STS と RP を所有するドメインの RP-STS が関与します。

またこのケースでは、RP-STS が理解できる、合意に基づくクレームを IP-STS が付与します。しかし、これらのクレームはそのままの形では RP アプリケーションで使用できないこともあります。そこで、RP-STS が別の信頼されたクレーム セットを RP のドメインで理解できるクレームに変換します。

図 14 にこのシナリオを示します。Joe がトークンのない状態で RP にアクセスを試みた場合、彼自身のドメイン (ドメイン B) にある IP-STS にログインすることになります。RP が理解できるクレーム (この場合は RPClaim) が要求されると、IP-STS は RP が使用できるトークンを発行する必要があることを認識します。このトークンを受け取った RP-STS は、そのクレームを RP 固有のクレームに変換します。このフェデレーション シナリオを実現するためには、RP-STS と IP-STS の間に信頼関係が必要です。また、RP-STS と IP-STS は、RP へのアクセス許可を付与するユーザーに対して IP-STS が発行すべきクレーム セットについて、合意する必要があります。

fig14.gif

図 14 フェデレーション シナリオにおけるクレームの変換

まとめ

Geneva Framework は、完全な機能を備えた STS プラットフォーム (Geneva Server など) は不要な、カスタム STS の構築に関心がある開発者にとって、願ってもないユーティリティです。しかし、Geneva Framework を使用したとしても、カスタム STS の構築は複雑な作業です。リスクを軽減するために、可能であれば完全な機能を備えた STS を使用することをお勧めします。

どのプラットフォームでも、アクティブおよびパッシブ STS の実装における通信フローは変わりません。クレームの変換の背後にあるアイデアも同様です。STS の実装に関係するその他の概念には、ID の委任やステップアップ認証などがあります。このような概念に関係するサンプルやドキュメントは、Geneva Framework SDK に含まれています。

Michele Leroux Bustamante は、IDesign Inc. の Chief Architect、サンディエゴ地域の Microsoft Regional Director、および Connected Systems の Microsoft MVP を兼任しています。彼女の最新の著書は『Learning WCF』です。連絡を取るには、mlb@idesign.net 宛てに電子メールを送るか、idesign.net にアクセスしてください。Michele のブログのアドレスは、dasblonde.net です。