次の方法で共有


信頼されたファサード サービス

このシナリオのサンプルでは、Windows Communication Foundation (WCF) セキュリティ インフラストラクチャを使用して、呼び出し元の ID 情報をあるサービスから別のサービスにフローする方法を示します。

ファサード サービスを使用してサービスから提供される機能をパブリック ネットワークに公開するのは、一般的なデザイン パターンです。ファサード サービスは、通常は境界ネットワーク (DMZ、非武装地帯、およびスクリーン サブネットとも呼ばれます) 内に存在し、ビジネス ロジックを実装して内部データにアクセスする、バックエンド サービスと通信します。ファサード サービスとバックエンド サービス間の通信チャネルはファイアウォールを通過し、通常は 1 つの目的のみに限定されます。

このサンプルは、次のコンポーネントで構成されています。

  • 電卓クライアント

  • 電卓ファサード サービス

  • 電卓バックエンド サービス

ファサード サービスは、要求を検証して呼び出し元を認証します。認証と検証が正常に完了すると、ファサード サービスは、境界ネットワークから内部ネットワークへの制御された通信チャネルを使用して、バックエンド サービスに要求を転送します。ファサード サービスは、転送される要求の一部として呼び出し元の ID に関する情報を格納し、バックエンド サービスがプロセスでこの情報を使用できるようにします。呼び出し元の ID は、メッセージの Security ヘッダー内部にある Username セキュリティ トークンを使用して送信されます。このサンプルでは、WCF セキュリティ インフラストラクチャを使用し、この情報を送信して Security ヘッダーから抽出します。

Aa355058.Important(ja-jp,VS.100).gif 注 :
バックエンド サービスは、ファサード サービスを信頼して呼び出し元を認証します。このため、バックエンド サービスは呼び出し元の再認証を行いません。つまり、ファサード サービスから転送された要求内の ID 情報を使用します。こうした信頼関係があるので、バックエンド サービスでは、転送メッセージが信頼されたソース (この場合はファサード サービス) から送信されことを確認するために、ファサード サービスを認証する必要があります。

実装

このサンプルには、通信パスが 2 つあります。1 つはクライアントとファサード サービス間のパスで、もう 1 つはファサード サービスとバックエンド サービス間のパスです。

クライアントとファサード サービス間の通信パス

クライアントとファサード サービスとの通信パスでは、UserName 型のクライアント資格情報が設定された wsHttpBinding を使用します。つまり、クライアントはユーザー名とパスワードを使用してファサード サービスに対する認証を行い、ファサード サービスは X.509 証明書を使用してクライアントに対する認証を行います。バインディング構成は次の例のようになります。

<bindings>
  <wsHttpBinding>
    <binding name="Binding1">
      <security mode="Message">
        <message clientCredentialType="UserName"/>
      </security>
    </binding>
  </wsHttpBinding>
</bindings>

ファサード サービスはカスタム UserNamePasswordValidator 実装を使用して、呼び出し元を認証します。この認証では、デモンストレーション用に、呼び出し元のユーザー名と指定されたパスワードが一致していることだけを確認します。実環境では多くの場合、Active Directory またはカスタムの ASP.NET メンバシップ プロバイダを使用して認証が行われます。検証の実装は FacadeService.cs ファイルにあります。

public class MyUserNamePasswordValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        // check that username matches password
        if (null == userName || userName != password)
        {
            Console.WriteLine("Invalid username or password");
            throw new SecurityTokenValidationException(
                       "Invalid username or password");
        }
    }
}

カスタム検証が、ファサード サービス構成ファイルの serviceCredentials 動作の内側で使用されるよう構成されます。この動作は、サービスの X.509 証明書の構成にも使用されます。

<behaviors>
  <serviceBehaviors>
    <behavior name="FacadeServiceBehavior">
      <!--The serviceCredentials behavior allows you to define -->
      <!--a service certificate. -->
      <!--A service certificate is used by the service to  -->
      <!--authenticate itself to its clients and to provide  -->
      <!--message protection. -->
      <!--This configuration references the "localhost"  -->
      <!--certificate installed during the setup instructions. -->
      <serviceCredentials>
        <serviceCertificate 
               findValue="localhost" 
               storeLocation="LocalMachine" 
               storeName="My" 
               x509FindType="FindBySubjectName" />
        <userNameAuthentication userNamePasswordValidationMode="Custom"
            customUserNamePasswordValidatorType=
           "Microsoft.ServiceModel.Samples.MyUserNamePasswordValidator,
            FacadeService"/>
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>

ファサード サービスと バックエンド サービス間の通信パス

ファサード サービスとバックエンド サービスとの通信パスでは、複数のバインディング要素で構成される customBinding を使用します。このバインディングにより、次の 2 つが実現されます。まず、ファサード サービスとバックエンド サービスが認証され、通信がセキュリティで保護されていることと、信頼されたソースからのものであることが確認されます。次に、Username セキュリティ トークン内にある、最初の呼び出し元の ID が送信されます。この場合、最初の呼び出し元のユーザー名だけがバックエンド サービスに送信されます。パスワードはメッセージには含まれません。これは、バックエンド サービスがファサード サービスに要求を転送する前に、ファサード サービスを信頼して呼び出し元を認証するためです。ファサード サービスはバックエンド サービスに対して自己認証を行うので、バックエンド サービスは転送された要求に含まれる情報を信頼できます。

この通信パスのバインディング構成は次のようになります。

<bindings>
  <customBinding>
    <binding name="ClientBinding">
      <security authenticationMode="UserNameOverTransport"/>
      <windowsStreamSecurity/>
      <tcpTransport/>
    </binding>
  </customBinding>
</bindings>

security バインディング要素により、最初の呼び出し元のユーザー名の送信および抽出が行われます。windowsStreamSecurity elementTcpTransport element により、ファサード サービスおよびバックエンド サービスの認証と、メッセージの保護が行われます。

要求を転送するには、WCF セキュリティ インフラストラクチャが、転送するメッセージに最初の呼び出し元のユーザー名を格納できるように、ファサード サービスの実装でこのユーザー名を提供する必要があります。最初の呼び出し元のユーザー名をファサード サービスの実装で提供するには、ファサード サービスがバックエンド サービスとの通信に使用するクライアント プロキシ インスタンスの ClientCredentials プロパティに、このユーザー名を設定します。

GetCallerIdentity メソッドをファサード サービスに実装する方法を次のコードに示します。他のメソッドも同じパターンを使用します。

public string GetCallerIdentity()
{
    CalculatorClient client = new CalculatorClient();
    client.ClientCredentials.UserName.UserName = ServiceSecurityContext.Current.PrimaryIdentity.Name;
    string result = client.GetCallerIdentity();
    client.Close();
    return result;
}

前のコードに示すように、ClientCredentials プロパティではパスワードは設定されず、ユーザー名のみが設定されています。この場合、WCF セキュリティ インフラストラクチャではユーザー名セキュリティ トークンが作成されますが、パスワードは指定されません。このシナリオで実際に必要となるのは、この設定です。

バックエンド サービスでは、ユーザー名セキュリティ トークンに含まれる情報が認証される必要があります。WCF セキュリティの既定では、指定されたパスワードを使用してユーザーを Windows アカウントに割り当てようとします。この場合、パスワードは指定されず、バックエンド サービスはユーザー名を認証する必要がありません。ファサード サービスで既に認証が行われているからです。この機能を WCF に実装するには、強制的にユーザー名をトークンで指定するだけでその他の認証を実行しない、カスタム UserNamePasswordValidator を指定します。

public class MyUserNamePasswordValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        // Ignore the password because it is empty, 
        // we trust the facade service to authenticate the client.
        // Accept the username information here so that the 
        // application gets access to it.
        if (null == userName)
        {
            Console.WriteLine("Invalid username");
            throw new 
             SecurityTokenValidationException("Invalid username");
        }
    }
}

カスタム検証が、ファサード サービス構成ファイルの serviceCredentials 動作の内側で使用されるよう構成されます。

<behaviors>
  <serviceBehaviors>
    <behavior name="BackendServiceBehavior">
      <serviceCredentials>
        <userNameAuthentication userNamePasswordValidationMode="Custom"
           customUserNamePasswordValidatorType=
          "Microsoft.ServiceModel.Samples.MyUserNamePasswordValidator, 
           BackendService"/>
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>

ユーザー名の情報と信頼されたファサード サービス アカウントに関する情報を抽出するには、バックエンド サービスの実装で ServiceSecurityContext クラスを使用します。GetCallerIdentity メソッドを実装する方法を次のコードに示します。

public string GetCallerIdentity()
{
    // Facade service is authenticated using Windows authentication.
    //Its identity is accessible.
    // On ServiceSecurityContext.Current.WindowsIdentity.
    string facadeServiceIdentityName = 
          ServiceSecurityContext.Current.WindowsIdentity.Name;

    // The client name is transmitted using Username authentication on 
    //the message level without the password
    // using a supporting encrypted UserNameToken.
    // Claims extracted from this supporting token are available in 
    // ServiceSecurityContext.Current.AuthorizationContext.ClaimSets 
    // collection.
    string clientName = null;
    foreach (ClaimSet claimSet in 
        ServiceSecurityContext.Current.AuthorizationContext.ClaimSets)
    {
        foreach (Claim claim in claimSet)
        {
            if (claim.ClaimType == ClaimTypes.Name && 
                                   claim.Right == Rights.Identity)
            {
                clientName = (string)claim.Resource;
                break;
            }
        }
    }
    if (clientName == null)
    {
        // In case there was no UserNameToken attached to the request.
        // In the real world implementation the service should reject 
        // this request.
        return "Anonymous caller via " + facadeServiceIdentityName;
    }

    return clientName + " via " + facadeServiceIdentityName;
}

ファサード サービス アカウント情報は、ServiceSecurityContext.Current.WindowsIdentity プロパティを使用して抽出されます。最初の呼び出し元に関する情報にアクセスするには、バックエンド サービスで ServiceSecurityContext.Current.AuthorizationContext.ClaimSets プロパティを使用します。そして、型 Name を含む Identity クレームを検索します。このクレームは、WCF セキュリティ インフラストラクチャによって、Username セキュリティ トークンに含まれる情報から自動的に生成されます。

サンプルの実行

このサンプルを実行する場合は、操作要求および応答はクライアントのコンソール ウィンドウに表示されます。クライアントをシャットダウンするには、クライアント ウィンドウで Enter キーを押します。ファサード サービスまたはバックエンド サービスのコンソール ウィンドウで Enter キーを押すと、サービスがシャットダウンされます。

Username authentication required.
Provide a valid machine or domain ac
   Enter username:
user
   Enter password:

user via MyMachine\testaccount
Add(100,15.99) = 115.99
Subtract(145,76.54) = 68.46
Multiply(9,81.25) = 731.25
Divide(22,7) = 3.14285714285714

Press <ENTER> to terminate client.

信頼されたファサード シナリオのサンプルに用意されている Setup.bat バッチ ファイルを使用すると、適切な証明書を使用してサーバーが構成され、クライアントに対して自己認証を行う証明書ベースのセキュリティが必要なファサード サービスを実行できるようになります。詳細については、このトピック末尾のセットアップ手順を参照してください。

次に、バッチ ファイルの各セクションの概要を簡単に説明します。

  • サーバー証明書の作成。

    Setup.bat バッチ ファイルの次の行は、使用するサーバー証明書を作成します。

    echo 
    echo Server cert setup starting
    echo %SERVER_NAME%
    echo 
    echo making server cert
    echo 
    makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=%SERVER_NAME% -sky exchange -pe
    

    %SERVER_NAME% 変数はサーバー名を指定します。既定値は localhost です。証明書は LocalMachine ストアに保存されます。

  • クライアントの信頼された証明書ストアへのファサード サービスの証明書のインストール。

    次の行は、ファサード サービスの証明書をクライアントの信頼されたユーザーのストアにコピーします。この手順が必要なのは、Makecert.exe によって生成される証明書がクライアント システムにより暗黙には信頼されないからです。マイクロソフト発行の証明書など、クライアントの信頼されたルート証明書に基づいた証明書が既にある場合は、クライアント証明書ストアにサーバー証明書を配置するこの手順は不要です。

    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
    

サンプルを設定、ビルド、および実行するには

  1. Windows Communication Foundation サンプルの 1 回限りのセットアップの手順」が実行済みであることを確認します。

  2. ソリューションの C# 版または Visual Basic .NET 版をビルドするには、「Windows Communication Foundation サンプルのビルド」の手順に従います。

サンプルを同じコンピュータで実行するには

  1. Makecert.exe が存在するフォルダがパスに含まれていることを確認します。

  2. Setup.bat をサンプルのインストール フォルダで実行します。これにより、サンプルの実行に必要なすべての証明書がインストールされます。

  3. 別のコンソール ウィンドウで、\BackendService\bin ディレクトリの BackendService.exe を起動します。

  4. 別のコンソール ウィンドウで、\FacadeService\bin ディレクトリの FacadeService.exe を起動します。

  5. Client.exe を \client\bin で起動します。クライアント アクティビティがクライアントのコンソール アプリケーションに表示されます。

  6. クライアントとサービス間で通信できない場合は、「Troubleshooting Tips」を参照してください。

サンプルの実行後にクリーンアップするには

  1. サンプルの実行が終わったら、サンプル フォルダにある Cleanup.bat を実行します。
Aa355058.Important(ja-jp,VS.100).gif 注 :
サンプルは、既にコンピューターにインストールされている場合があります。続行する前に、次の (既定の) ディレクトリを確認してください。

<InstallDrive>:\WF_WCF_Samples

このディレクトリが存在しない場合は、「.NET Framework 4 向けの Windows Communication Foundation (WCF) および Windows Workflow Foundation (WF) のサンプル」にアクセスして、Windows Communication Foundation (WCF) および WF のサンプルをすべてダウンロードしてください。このサンプルは、次のディレクトリに格納されます。

<InstallDrive>:\WF_WCF_Samples\WCF\Scenario\TrustedFacade