TrustedFacade サンプルでは、Windows Communication Foundation (WCF) セキュリティ インフラストラクチャを使用して、呼び出し元の ID 情報をサービス間でフローする方法を示します。
ファサード サービスを使用して、サービスによって提供される機能をパブリック ネットワークに公開することは、一般的な設計パターンです。 ファサード サービスは通常、境界ネットワーク (DMZ、非武装地帯、スクリーン サブネットとも呼ばれます) に存在し、ビジネス ロジックを実装し、内部データにアクセスできるバックエンド サービスと通信します。 ファサード サービスとバックエンド サービスの間の通信チャネルはファイアウォールを通過し、通常は単一の目的でのみ制限されます。
このサンプルは、次のコンポーネントで構成されています。
電卓クライアント
電卓ファサード サービス
Calculator バックエンド サービス
ファサード サービスは、要求を検証し、呼び出し元を認証する役割を担います。 認証と検証が成功すると、制御された通信チャネルを使用して境界ネットワークから内部ネットワークに要求がバックエンド サービスに転送されます。 転送された要求の一部として、ファサード サービスには、バックエンド サービスがその処理でこの情報を使用できるように、呼び出し元の ID に関する情報が含まれます。 呼び出し元の ID は、メッセージ Username
ヘッダー内のSecurity
セキュリティ トークンを使用して送信されます。 このサンプルでは、WCF セキュリティ インフラストラクチャを使用して、 Security
ヘッダーからこの情報を送信および抽出します。
Von Bedeutung
バックエンド サービスは、ファサード サービスを信頼して呼び出し元を認証します。 このため、バックエンド サービスは再び呼び出し元を認証しません。転送された要求でファサード サービスによって提供される ID 情報が使用されます。 この信頼関係のため、バックエンド サービスはファサード サービスを認証して、転送されたメッセージが信頼できるソース (この場合はファサード サービス) から送信されるようにする必要があります。
実装
このサンプルには、2 つの通信パスがあります。 1 つ目はクライアントとファサード サービスの間、2 つ目はファサード サービスとバックエンド サービスの間です。
クライアントとファサード サービス間の通信パス
クライアントとファサード サービスとの通信パスでは、 wsHttpBinding
型のクライアント資格情報が設定された UserName
を使用します。 つまり、クライアントはユーザー名とパスワードを使用してファサード サービスに対して認証を行い、ファサード サービスは 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> と <tcpTransport> は、ファサードサービスとバックエンド サービスとメッセージ保護の認証を行います。
要求を転送するには、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
プロパティを使用します。 そして、型 Identity
を含む Name
クレームを検索します。 この要求は、 セキュリティ トークンに含まれる情報から WCF セキュリティ インフラストラクチャによって自動的に生成されます。
サンプルの実行
サンプルを実行すると、操作要求と応答がクライアント コンソール ウィンドウに表示されます。 クライアント ウィンドウで 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 によって生成された証明書はクライアント システムによって暗黙的に信頼されないため、この手順が必要です。 クライアントの信頼されたルート証明書 (Microsoft が発行した証明書など) にルート化された証明書が既にある場合、クライアント証明書ストアにサーバー証明書を設定するこの手順は必要ありません。
certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
サンプルを設定、ビルド、実行するには
Windows Communication Foundation サンプル のOne-Time セットアップ手順を実行していることを確認します。
ソリューションの C# または Visual Basic .NET エディションをビルドするには、「Windows Communication Foundation サンプルのビルド」の手順に従います。
同じコンピューターでサンプルを実行するには
パスに、Makecert.exe が配置されているフォルダーが含まれていることを確認します。
サンプルのインストール フォルダーから Setup.bat を実行します。 これにより、サンプルの実行に必要なすべての証明書がインストールされます。
別のコンソール ウィンドウで \BackendService\bin ディレクトリから BackendService.exe を起動する
別のコンソール ウィンドウで \FacadeService\bin ディレクトリから FacadeService.exe を起動する
\client\bin から Client.exe を起動します。 クライアント アクティビティがクライアント コンソール アプリケーションに表示されます。
クライアントとサービスが通信できない場合は、「WCF サンプルのトラブルシューティングのヒント」を参照してください。
サンプルの実行後にクリーンアップするには
- サンプルの実行が完了したら、samples フォルダーで Cleanup.bat を実行します。