Windows Workflow

WF 4 ワークフロー サービスのセキュリティを確保する

Zulfiqar Ahmed

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

Windows Workflow Foundation (WF) は、ソフトウェア ロジックを目に見える形で作成できるようにします。ソフトウェア ロジックをワークフローとして実装したら、ワークフロー ホストでそのワークフローをホストすることによって実行します。ワークフロー サービスは、ワークフローを使用して実装される特殊な Web サービスで、WorkflowServiceHost でこのワークフロー サービスをホストすることにより、コンシューマーから使用できるようになります。今回の記事では、さまざまなワークフロー ホストのセキュリティ オプションについて、ワークフロー サービスと WorkflowServiceHost に特に重点を置いて説明します。ワークフロー サービスのセキュリティ境界をワークフロー層まで拡張するために使用できる、いくつかの主要拡張ポイントについても説明します。また、Workflow Security Pack (WFSP) プロジェクトを紹介しながら、そのアクティビティのコレクションを使用して、ワークフロー ソリューションにエンド ツー エンドのセキュリティを確保する方法についても説明します。Microsoft .NET Framework 4 に付属する WF 4 は、拡張可能なホスティング API と、さまざまな機能を備えた組み込みの 3 つのワークフロー ホストを提供します。

WorkflowInvoker: 最も基本的で、機能が最も少ないホスト インターフェイスで、ワークフローを呼び出すための簡単な API を提供します。WorkflowInvoker オブジェクトは、コンストラクターまたは静的 Invoke メソッドを通じて渡されるワークフロー インスタンスを 1 つだけサポートします。すべてのワークフローは、呼び出し元の同じスレッドで実行されることが保証されるため、呼び出し元のコードの特定のセキュリティ コンテキストが偽装されると、この偽装されたコンテキストですべてのアクティビティが実行されることになります。WorkflowInvoker は、真の意味でのワークフロー ホストとは言えません。どちらかと言えば、WorkflowApplication ベースのホストをカプセル化し、ポンプに基づく同期コンテキストを使用して、使いやすい API と一貫した実行セマンティクスを提供するホストです。たとえば、例外やトランザクションなどは、呼び出しの境界をまたがってシームレスに流れます。この動作によりセキュリティが簡素化され、ワークフローの実行全体で呼び出し元のセキュリティ コンテキストを使用できるため、アクティビティはセキュリティのさまざまなシナリオでこのコンテキストを使用できます。たとえば、PrincipalPermission による承認と Kerberos 委任は、WorkflowInvoker とシームレスに機能します。

WorkflowApplication: わずかに機能が追加されていますが、依然として 1 つのインスタンスしかサポートしません。このホストは、CLR ThreadPool の IO スレッドを使用してワークフローを実行します。呼び出し元スレッドのセキュリティ コンテキストがワークフロー スレッドにコピーされないため、ワークフロー クライアントが偽装されたとしても、アクティビティを実行している WF スレッドは偽装されません。呼び出し元のセキュリティ コンテキストは、以下のように、カスタム同期コンテキストを使用して WF のスレッドに渡すことができます。このカスタム同期コンテキストは、WorkflowInvoker で使用される同期コンテキストと同様、同じ着信非同期スレッドでの呼び出しを転送します。

public class MySyncContext : SynchronizationContext
{
  public override void Post(SendOrPostCallback d, object state)
  {
    d(state);
  }
}

WorkflowServiceHost: 最も包括的なホストで、ワークフローの複数のインスタンスに適したホスティング環境を提供します。ワークフロー サービスは、その実装がワークフローに基づく、特殊な種類の Web サービスです。WorkflowServiceHost は、標準の Windows Communication Foundation (WCF) ServiceHostBase クラスから派生するため、WCF セキュリティのすべての概念が WorkflowServiceHost にも適用されます。メッセージングのアクティビティは、WorkflowHostingEndpoint と並んで、WorkflowServiceHost によってサポートされる主要対話モデルです。WorkflowHostingEndpoint は、メッセージングのアクティビティを使用することなく、WorkflowServiceHost の使用を可能にします。今回の記事では、主に、メッセージングのアクティビティ、ワークフロー サービス、および WorkflowServiceHost のセキュリティ面に重点を置いて説明します。ワークフロー サービス テクノロジの概要については、Leon Welicki 氏が執筆した 2010 年 3 月号の MSDN マガジンの記事「WCF と WF 4 によるワークフローのビジュアル デザイン」(msdn.microsoft.com/magazine/ff646977) を参照してください。

ワークフロー サービスのネットワーク セキュリティ

ワークフロー サービスは標準の WCF サービスなので、ネットワーク セキュリティの側面は、WCF の標準バインディング メカニズムを使用して構成します。ワークフロー サービスは、サービスのセキュリティ要件ごとにそれぞれ特定のバインディングを使用する、1 つまたは複数のエンドポイントを使用して公開できます。WCF のディスパッチ パイプラインは、受信メッセージがターゲット エンドポイントのセキュリティ要件を満たしている場合のみ実行されます。ワークフロー ロジックは、ディスパッチ パイプラインの最後に実行されるため、一般的な WCF 拡張ポイントはすべてワークフロー サービスにも適用可能です。たとえば、標準の ServiceAuthorizationManager 拡張ポイントは、ワークフロー サービスに承認を適用するためにも使用できます。Windows Identity Foundation (WIF) などのフレームワークをディスパッチャー レベルで WCF と統合し、ユーザーが意識することなしに、これらをワークフロー サービスと併用できます。WCF 層と WF 層の間に存在するいくつかの非同期ポイントに関して、スレッド処理にいくぶん違いがあります。そのため、ワークフロー サービスにおける特定のスレッド ローカル記憶域 (TLS) に関連するシナリオがやや難しくなります。たとえば、WIF は、受信する ID 情報を Thread.CurrentPrincipal を使用して公開し、この ID 情報をコード ベースのサービスに適切に設定できるようにします。ただし、ワークフロー ロジックは、元の WCF のスレッドとは異なるスレッドで実行されることになる場合があります。その場合は、Thread.CurrentPrincipal を含むすべての TLS 関連のデータが有効にならないため、ワークフローでは TLS に依存しないことをお勧めします。この問題のいくつかの解決策については、記事の後半で説明します。

また、WF 4 は、ワークフロー内から他の Web サービスを呼び出すための Send アクティビティを提供します。Send アクティビティは、ワークフロー内から他のサービスを呼び出すときに使用することになるバインディングを使って構成できます。内部的には、Send アクティビティは、標準の WCF ChannelFactory/Channel API を使用してメッセージを送信するため、構成したバインディングはこの内部チャネル ファクトリの作成に使用されます。Send アクティビティには、ChannelFactory/Channel キャッシュに使用する、組み込みのキャッシュ層もあります。既定では、Send アクティビティのプロパティを使用してエンドポイント情報を直接指定し、構成したバインディングが選択されている場合のみ、このキャッシュ層が使用されます (図 1 参照)。

図 1 Send アクティビティのプロパティ

EndpointConfigurationName プロパティを使用して、構成ファイルからエンドポイント情報が読み込まれると、即座にセキュリティ保護されたキャッシュが無効になり、Send アクティビティが実行されるたびに新しくチャネル ファクトリが作成されます。wsHttpBinding や wsFederationHttpBinding といったセキュリティ保護されたバインディングでは、チャネル ファクトリを開く段階でかなり多くの処理が行われるため、メッセージごとにチャネル ファクトリが再作成されるとかなりのコストがかかることになります。たとえば、既定の WSHttpBinding はパフォーマンスとセキュリティを向上するために最適化されます。この最適化は、セキュリティ保護されたメッセージ交換セッションを最初にコストをかけて確立し、それに続くメッセージをはるかに少ないコストでセキュリティ保護することによって実現されます。すべてのビジネス メッセージでは、4 つの追加インフラストラクチャ メッセージを送信してサービス資格情報をネゴシエーションしてからセキュリティ保護されたメッセージ交換セッションが確立するため、チャネル ファクトリのキャッシュがなければ、WSHttpBinding のこの最適化動作がオーバーヘッドになります (図 2 参照)。

図 2 サービス資格情報をネゴシエーションするために送信されるインフラストラクチャ メッセージ

https://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue
https://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue
https://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT
http://tempuri.org/IPingService/Ping
https://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT/Cancel

WF 4 では、構成ファイルから読み込まれるすべてのバインディング構成 (既定のバインディングも含む) が、Send アクティビティによって "安全にキャッシュされない" と見なされ、チャネル ファクトリのキャッシュが無効になります。この既定の動作は、セキュリティ保護されていないチャネル キャッシュを強制的に使用することでオーバーライドできます。その結果、同じエンドポイントへのメッセージ送信にチャネル ファクトリが再利用されることになります。SendMessageChannelCache サービス ビヘイビアは、セキュリティ保護されていないキャッシュを有効にし、さまざまなチャネルやチャネル ファクトリのキャッシュ設定の構成を可能にします (下図参照)。

<serviceBehaviors>
  <behavior>
    <sendMessageChannelCache allowUnsafeCaching="true">
      <channelSettings idleTimeout="1:0:0" maxItemsInCache="60"/>
      <factorySettings idleTimeout="1:0:0" maxItemsInCache="60"/>
    </sendMessageChannelCache>
  </behavior>
</serviceBehaviors>

OperationContext のスコープ

従来のコード ベースのサービスでは、着信呼び出しのセキュリティ情報は OperationContext.Current を通じて使用できます。WCF ディスパッチャーのランタイムは、サービス メソッドを呼び出す直前にスレッドの OperationContext を設定するため、サービス メソッド内部では、OperationContext.Current を使用してセキュリティ情報にアクセスできます。

WCF ディスパッチャーとワークフローの実行の間に一連の非同期ポイントが存在するため、ワークフロー サービスの複雑さが増加します。これらの非同期ポイントのうちのいずれか 1 つでスレッドを切り替わる可能性があります。その場合、ワークフロー ロジック (アクティビティ) が WCF のスレッドとは異なるスレッドで実行され、OperationContext.Current 手法を使用して OperationContext を使用することができなくなります。WF 4 では、IReceiveMessageCallback と ISendMessageCallback に基づくコールバック メカニズムを使用して、実行されるスレッドとは無関係に OperationContext へのアクセスを可能にします。IReceiveMessageCallback はサーバー側、ISendMessageCallback はクライアント側の OperationContext へのアクセスを可能にします。サーバー側では、Receive アクティビティでメッセージを受信した直後に、IReceiveMessageCallback が呼び出されます。これらのコールバックを Send アクティビティと Receive アクティビティにアタッチするには、Send および Receive の実行時に、これらのコールバックを実行プロパティとして使用できなければなりません。アクティビティに実行プロパティを追加する一般的な方法は、親スコープのアクティビティを作成し、実行プロパティを親アクティビティの実行の一環として設定することです (図 3 参照)。

図 3 実行プロパティを追加するシンプルなスコープ アクティビティ

[ContentProperty("Body")]
public sealed class OperationContextScope : NativeActivity
{
  public Activity Body { get; set; }
  protected override void Execute(NativeActivityContext context)
  {
    if (this.Body != null)
    {
      // Adding an execution property to handle OperationContext
      context.Properties.Add(OperationContextScopeProperty.Name,
        new OperationContextScopeProperty());
      context.ScheduleActivity(this.Body);
    }
  }
}

図 3 のコード スニペットでは、OperationContextScope アクティビティの実行時に、実行プロパティをコンテキストに追加して、すべての子アクティビティがこの実行プロパティを認識できるようにします。Send アクティビティと Receive アクティビティは、前述のコールバックのプロパティを探します。これらのプロパティのうちの 1 つが見つかれば、メッセージ処理の適切な段階でこのプロパティを呼び出して、OperationContext にアクセスできるようになります。この例では、同じスコープに含まれるすべての Receive アクティビティが OperationContextScopeProperty を認識し、OperationContext の値を渡してコールバックを実行します (図 4 参照)。

図 4 実行プロパティとして実装される ReceiveMessageCallback

[DataContract]
class OperationContextScopeProperty : IReceiveMessageCallback,  IExecutionProperty
{
  private OperationContext current;
  private OperationContext orignal;

  public static readonly string Name = 
    typeof(OperationContextScopeProperty).FullName;
  public void OnReceiveMessage(OperationContext operationContext, 
    ExecutionProperties activityExecutionProperties)
  {
    current = operationContext;
    operationContext.OperationCompleted 
      += delegate(object sender, EventArgs e)
    {
      current = null;
    };
  }

  public void CleanupWorkflowThread()
  {
    OperationContext.Current = orignal;
  }
  public void SetupWorkflowThread()
  {
    orignal = OperationContext.Current;
    OperationContext.Current = current;
    }
}

OperationContextScopeProperty は、単純に、現在アクティブな OperationContext をキャプチャして格納し、後で、WF の TLS メカニズムを使用して、適切な WF スレッドでこれを設定します。IExecutionProperty インターフェイスには、SetupWorkflowThread メソッドと CleanUpWorkflowThread メソッドがあります。これは、あらゆる WF の作業項目 (アクティビティ) の実行前後に呼び出され、選択された WF スレッドでさまざまな TLS 関連のプロパティを設定できるようにします。設定されるプロパティの一例が、この場合の OperationContext です。

OperationContextScope は、WF 4 拡張機能を使用するカスタム アクティビティの一例で、実行するスレッドとは関係なく、スコープ内のすべての子アクティビティに、WCF OperationContext へのアクセスを可能にします。

ワークフロー サービスと WIF

WIF は、WCF サービスと ASP.NET アプリケーションをクレーム対応にする、豊富な API とオブジェクト モデルを提供します。WIF は WCF とホスト レベルで統合されるため、WIF のほとんどの機能がワークフロー サービスと連携します。WIF とワークフロー サービスの統合の詳細については、私のブログの記事 (bit.ly/a6pWgA、英語) を参照してください。この組み込みの統合は基本的なシナリオではうまく機能しますが、機能が豊富に追加されるシナリオを可能にするには、WFSP のアクティビティを使用します。

WFSP CTP 1 の概要

WFSP Community Technology Preview (CTP) 1 は、WF 4 の主なセキュリティ シナリオを可能にするため、アクティビティのコレクションと関連する WCF ビヘイビアを提供します。WFSP は、ISendMessageCallback と IReceiveMessageCallback の拡張モデルを使用して、その多くの機能を実装しています。WFSP の CTP 1 は、2010 年 7 月に CodePlex からリリースされています (wf.codeplex.com/releases/view/48114 (英語) からダウンロード可能)。

図 5 に示す WFSP のアクティビティは、他の WF と適切に統合され、統合セキュリティをワークフロー ソリューションにもたらす強力な構造を提供します。

image: Workflow Security Pack Activities

図 5 Workflow Security Pack のアクティビティ

ワークフロー内での承認

ワークフロー サービスでは、標準の WCF ServiceAuthorizationManager 拡張機能を使用して承認を強制することができ、コードベースのサービスとまったく同じように機能します。ただし、一部のシナリオ (たとえば、承認データがワークフローに含まれるシナリオ) では、実際にワークフローを実行するまで承認の決定を遅らせることになります。PrincipalPermissionScope は、CLR の PrincipalPermission の承認機能をワークフローにもたらす、サーバー側のアクティビティです。スコープ内に配置されたすべての子アクティビティは、アクセス許可要求が成功した場合のみ実行されます。このアクティビティは、OperationContext からアクセスされる着信 WCF セキュリティ コンテキスト内で ID 情報を探します。PrincipalPermissionScope は、記事前半で説明したのと同じ IReceiveMessageCallback メカニズムを使用して実装されます。

実際の PrincipalPermission 要求は、ServiceAuthorizationBehavior.PrincipalPermissionMode の値に基づいて、IPrincipal オブジェクトに対して強制されます。この拡張機能により、PrincipalPermissionScope と ASP.NET ロール プロバイダーが連携し、カスタム IAuthorizationPolicy によって生成されるカスタム IPrincipal 実装とも連携します。WCF サービスを使用して ASP.NET ロール プロバイダーを構成する方法の詳細については、msdn.microsoft.com/library/aa702542 を参照してください。

メッセージングのアクティビティと認証を受けるメッセージング

Send アクティビティは、ワークフロー内から Web サービスを使用する基本手法を提供します。実際のシナリオの大半では、このようなバックエンド サービスがセキュリティ保護されるため、処理の実行前に認証が必要になります。標準のコードベースのサービスでは、ChannelFactory と ClientBase<T> の派生プロキシ クラスで公開される ClientCredential プロパティを使用して、資格情報を指定します。このプロパティを使用すれば、クライアントはサービスを呼び出す前に、使用する資格情報を指定できます。残念ながら、ChannelFactory をラップする Send アクティビティは、WF 4 の ClientCredential を公開しないため、明示的に資格情報を指定する必要がある一部のシナリオでは、そのまま Send アクティビティを使用することができません。Send アクティビティは、構成ファイルからエンドポイント ビヘイビアの構成を選択するため、カスタム エンドポイント ビヘイビアを作成すれば、このような資格情報を指定できます。

明示的な資格情報を必要とする代表的な例は、ユーザー名とパスワードを要求するよう構成されたサービスを呼び出す場合です。ClientCredential プロパティが Send アクティビティで公開されないため、ユーザー名とパスワードを指定する方法がありません。では、このシナリオとその他の関連シナリオに対して、WFSP の GetUserNameSecurityToken アクティビティがどのような解決策を提供するかを見てみましょう。

図 6 では、サービス参照の追加ウィザードで Ping アクティビティを生成しています。以下のバインディング構成に示すように、ユーザー名による認証を必要とすることでセキュリティ保護されているサービスを呼び出すように構成しています。

<wsHttpBinding>
  <binding name="singleShotUserName">
    <security mode="Message">
      <message clientCredentialType="UserName" establishSecurityContext
        ="false" />
    </security>
  </binding>
</wsHttpBinding>

image: Authenticated Messaging Using a UserName Token

図 6 UserName トークンを使用して認証を受けるメッセージング

上記のワークフローでは、GetUserNameSecurityToken はここで指定されたユーザー名とパスワードに基づいて UserNameSecurityToken を作成し、TokenFlowScope アクティビティによって提供されるその環境の SecurityTokenHandle にこのトークンを登録します。"Workflow Security Pack" は、セキュリティを資格情報のレベルで適用する ChannelFactory と ClientBase<T> のアプローチとは対照的に、SecurityToken レベルでセキュリティを適用します。標準の WCF では、セキュリティ トークンの作成に資格情報を使用しますが、WFSP はセキュリティ トークンを直接使用して、資格情報レベルではなくトークン レベルで、WCF のセキュリティ層にアクセスします。

TokenFlowScope は、認証を受けるメッセージングなどの興味深いシナリオを可能にする重要なアクティビティです。このアクティビティは、WorkflowClientCredentials エンドポイント ビヘイビアと共に、登録済みのトークンをワークフロー層から WCF のセキュリティ層に渡します。WCF セキュリティ層では、エンドポイントのバインディング要件ごとに、これらのトークンを送信メッセージにアタッチします。TokenFlowScope では、以下の構成スニペットに示すように、ClientCredential のカスタム ビヘイビア (WorkflowClientCredentials) を構成する必要があります。

<behavior>
   <!--This custom clientCredentials enables the credential flow from 
     workflow data model into WCF security layer. -->
   <clientCredentials
     type="Microsoft.Security.Activities.WorkflowClientCredentials, 
     Microsoft.Security.Activities, Version=1.0.0.0, Culture=neutral, 
     PublicKeyToken=31bf3856ad364e35">
   </clientCredentials>
</behavior>

WFSP は、セキュリティ トークン サービス (STS) からのトークンを必要とするサービスを呼び出すときに、この厳密なモデルに従います (図 7 参照)。

image: Fine-Grained Control of SAML Token Acquisition and Usage

図 7 SAML トークンの取得と使用のきめ細かい制御

図 7 では、GetSamlSecurityToken が発行者となり、SAML トークンを取得します。その後、このトークンは、TokenFlowScope アクティビティによって提供されるその環境のハンドルに登録されます。このような登録により、同じスコープ内にあり、SAML トークンを要求するすべての Send アクティビティでこのトークンを使用できるようになります。このモデルは拡張可能で、たとえば、SAML トークンを返すために STS が UserName トークンを必要とする場合や、有効な UserName トークンがスコープに既に登録されている場合などは、SAML トークンを取得する一方で、GetSamlSecurityToken 自体が登録済みのトークンを使用できます。WorkflowClientCredentials ビヘイビアを構成すれば、SAML トークンを要求するときに GetSamlSecurityToken がこのトークンを使用するようになります。

組み込みの WFSP は、トークンの種類として UserName と SAML しかサポートしません。ただし、GetSecurityToken クラスから継承することで、他の種類のトークンを有効にできます (図 8 のコード スニペット参照)。GetSecurityToken クラスは、X509 ベースのトークンを作成するためのアクティビティを実装しします。

図 8 WFSP の拡張機能: その他の種類のトークンの実装

[Designer(typeof(GetX509SecurityTokenDesigner))]
public class GetX509SecurityToken : GetSecurityToken
{
  public GetX509SecurityToken()
  {
    FindType = X509FindType.FindBySubjectName;
    StoreLocation = StoreLocation.CurrentUser;
    StoreName = StoreName.My;
  }

  public InArgument<X509Certificate2> Certificate { get; set; }
  public X509FindType FindType { get; set; }
  public StoreLocation StoreLocation { get; set; }
  public InArgument<string> FindValue { get; set; }
  public StoreName StoreName { get; set; }

  protected override void Execute(NativeActivityContext context)
  {
    X509Certificate2 targetCert = null;
    if (this.Certificate != null)
      targetCert = this.Certificate.Get(context);
    if (targetCert == null)
    {
      var store = new X509Store(StoreName, StoreLocation);
      try
      {
        store.Open(OpenFlags.ReadOnly);
        var col = store.Certificates.Find(FindType, FindValue.Get(context), false);
        if (col.Count > 0)
          targetCert = col[0];//Use first certificate mathing the search criteria
      }
      finally
      {
        if (store != null)
          store.Close();
      }
    }
    if (targetCert == null)
      throw new InvalidOperationException(
        "No certificate found using the specified find criteria.");
        // Enlist the token as a flow token
      base.EnlistSecurityToken(context, new X509SecurityToken(targetCert));
  }
}

GetX509SecurityToken は、資格情報を基に X509Security トークンを作成し、このトークンをフロー トークンとして SecurityTokenHandle に登録します。このトークンは、認証のために資格情報が必要なサービスを呼び出すために使用できます。図 9 に、使用中の GetX509SecurityToken とカスタム アクティビティ デザイナーを示します。

image: TokenFlowScope with a Custom GetToken Activity

図 9 TokenFlowScope とカスタム GetToken アクティビティ

クレームベースの委任

クレームベースの委任は、WFSP で可能になるもう 1 つの有益な機能です。クレームベースの委任は、ワークフロー サービスにとってより好ましい場合がほとんどです。というのも、ワークフロー サービスは、基本的に、複数のバックエンド サービスを呼び出すオーケストレーション/ビジネス プロセスを実装するためです。さらに、多くの場合、きめ細かい承認の決定を可能にするために、こうしたバックエンド サービスでの呼び出し元 ID へのアクセスが必要になります。WFSP は、WS-Trust 1.4 の ActAs 機能を利用して、すべての種類のトークンを ActAs トークンとして使用するようにできます。既定では、すべての GetToken アクティビティがトークンを作成し、そのトークンをフロー トークンとして登録します。ただし、これらのすべてのアクティビティには、IsActAsToken というフラグも含まれます (図 10 参照)。

image: Creating an ActAs Token

図 10 ActAs トークンの作成

このフラグのチェック ボックスをオンにすると、トークン作成ロジックは変わりませんが、作成されるトークン T1 がフロー トークンではなく ActAs トークンとして登録されます。ActAs トークンはスコープごとに 1 つだけで、SAML トークンを要求しているときに、GetSamlSecurityToken アクティビティによって使用されます。GetSamlSecurityToken の実行時に、アクティブな ActAs トークンが選択され、GetSamlSecurityToken アクティビティによって生成されるトークン発行要求の一部として送信されます。返されるトークン T2 には、認証トークンと ActAs トークンの両方からのクレームが含まれることになります。最後に、セキュリティ コンテキスト内で両方の ID を確認するバックエンド サービスを呼び出すときに、このスコープ内で実行されるすべての Send アクティビティで、この T2 トークンを使用できます。

GetBootstrapToken アクティビティは、中間層のシナリオで使用して、エンド ツー エンドのクレームベースの委任を可能にします。GetToken アクティビティとは対照的に、このアクティビティは、新しいトークンを作成して登録するのではなく、着信するトークンを読み取り、このトークンを ActAs トークンとして登録します。GetBootstrapToken アクティビティにより、ワークフロー サービスは、バックエンド サービスを呼び出すときに、独自の ID に加えて、着信する呼び出し側の ID も使用できます (図 11 参照)。

image: End-to-End Claims-Based Delegation Flow

図 11 エンド ツー エンドのクレームベースの委任の流れ

図 11 の手順 3. では、ワークフロー サービスが WFSP のアクティビティを使用して、着信するブートストラップ トークンを読み取り、ブートストラップ トークンの ID として機能する新しいトークンを取得して、両方の ID をバックエンド サーバーに渡します。図 12 に、このワークフロー サービスで使用されるワークフローを示します。

image: Claims-Based Delegation Workflow

図 12 クレームベースの委任のワークフロー

図 12 のワークフローでは、GetBootstrap アクティビティが OperationContextScope 内に配置され、このアクティビティを実行するときに、実行されるスレッドとは関係なく、OperationContext へのアクセスが保証されます。GetSamlSecurityToken は、前の手順で GetBootstrapToken によって生成された ActAs トークンを使用して、最終的に、GetSamlSecurityToken アクティビティによって生成された最終的な SAML トークンを使用して、Echo アクティビティからバックエンド サービスを呼び出します。

Windows の偽装と委任

ImpersonatingReceiveScope は、サーバー側のもう 1 つのアクティビティです。これにより、ワークフロー環境に Windows の偽装と委任が提供されます。このアクティビティの実行時に、着信するセキュリティ コンテキスト内で WindowsIdentity を探します。着信メッセージによって WindowsIdentity が生成される場合、この偽装されたスコープ内で、本文の一部であるすべての子アクティビティが実行されます。ImpersonatingReceiveScope は、この記事の前半で説明したワークフローの TLS メカニズムを使用して、作業項目の実行直前に、WF のスレッドで ID を偽装します。偽装は、WF の作業項目の実行が完了したら元に戻されます。

着信するセキュリティ コンテキストで有効な WindowsIdentity が見つからなければ、ImpersonatingReceiveScope は、WIF の ID (Thread.CurrentPrincipal) か従来の WCF ClaimSet のいずれかで UPN クレームを探し、これを使用して、Kerberos の S4U 機能を使用する WindowsToken を作成します。UPN クレームを Windows トークンに変換するために、ImpersonatingReceiveScope は "Claims to Windows Token Service" に依存します。これは、WIF ランタイムの一部です。クレームからトークンへの変換を正常に行うには、このサービスがインストールされて実行されている必要があります。

図 13 に、ImpersonatingReceiveScope アクティビティの一般的な使用例を示します。

image: ImpersonatingRecieveScope in Action

図 13 動作中の ImpersonatingRecieveScope

エンド ツー エンドのセキュリティ

見た目では、ワークフロー サービスは標準の WCF サービスなので、WCF のほとんどのセキュリティ オプションをワークフロー サービスにも適用できます。WF 4 では、ワークフロー サービスのセキュリティ境界をワークフロー層まで拡張するのに使用できる、主要な拡張ポイントがいくつか導入されています。WFSP は、このような拡張ポイントを使用して WF 4 でエンド ツー エンドのセキュリティを実現する、一連のアクティビティを提供します。

Zulfiqar Ahmed は、プレミア サポート チームのシニア コンサルタントであり、Workflow Security Pack プロジェクトの作成者でもあります。彼のブログは zamd.net (英語) にあります。このブログでは、Windows Communication Foundation、Windows Workflow Foundation、およびクレームベースのセキュリティから、一般的な Microsoft .NET Framework に関する記事まで、さまざまなトピックを取り上げています。

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