DurableIssuedTokenProvider サンプルは、カスタム クライアント発行トークン プロバイダーを実装する方法を示しています。
議論
Windows Communication Foundation (WCF) のトークン プロバイダーは、セキュリティ インフラストラクチャに資格情報を提供するために使用されます。 一般に、トークン プロバイダーはターゲットを調べ、適切な資格情報を発行して、セキュリティ インフラストラクチャがメッセージをセキュリティで保護できるようにします。 WCF には CardSpace トークン プロバイダーが付属しています。 カスタム トークン プロバイダーは、次の場合に役立ちます。
組み込みのトークン プロバイダが連係動作できない資格情報ストアがある場合。
ユーザーが詳細を提供した時点から WCF クライアントが資格情報を使用する時点まで、資格情報を変換するための独自のカスタム メカニズムを提供する場合。
カスタム トークンを構築する場合。
このサンプルでは、セキュリティ トークン サービス (STS) によって発行されたトークンをキャッシュするカスタム トークン プロバイダーを構築する方法を示します。
要約すると、このサンプルでは次の例を示します。
カスタム トークン プロバイダーを使用してクライアントを構成する方法。
発行されたトークンをキャッシュして WCF クライアントに提供する方法。
サーバーの X.509 証明書を使用してクライアントによってサーバーが認証される方法。
このサンプルは、クライアント コンソール プログラム (Client.exe)、セキュリティ トークン サービス コンソール プログラム (Securitytokenservice.exe) とサービス コンソール プログラム (Service.exe) で構成されています。 このサービスは、要求/応答通信パターンを定義するコントラクトを実装します。 コントラクトは、算術演算 (加算、減算、乗算、除算) を公開する ICalculator
インターフェイスによって定義されます。 クライアントは、セキュリティ トークン サービス (STS) からセキュリティ トークンを取得し、特定の算術演算に対してサービスに同期要求を行い、サービスは結果と共に応答します。 クライアント アクティビティはコンソール ウィンドウに表示されます。
注
このサンプルのセットアップ手順とビルド手順は、このトピックの最後にあります。
このサンプルでは、 <wsHttpBinding> を使用して ICalculator コントラクトを公開します。 クライアントでのこのバインディングの構成を次のコードに示します。
<bindings>
<wsFederationHttpBinding>
<binding name="ServiceFed">
<security mode="Message">
<message issuedKeyType="SymmetricKey"
issuedTokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1">
<issuer address="http://localhost:8000/sts/windows"
binding="wsHttpBinding" />
</message>
</security>
</binding>
</wsFederationHttpBinding>
</bindings>
security
のwsFederationHttpBinding
要素では、mode
値によって使用するセキュリティ モードが構成されます。 このサンプルでは、メッセージセキュリティが使用されているため、message
のwsFederationHttpBinding
要素がsecurity
のwsFederationHttpBinding
要素内で指定されています。
issuer
のwsFederationHttpBinding
要素内のmessage
のwsFederationHttpBinding
要素は、クライアントが Calculator サービスに対して認証できるように、クライアントにセキュリティ トークンを発行するセキュリティ トークン サービスのアドレスとバインドを指定します。
サービスでのこのバインドの構成を次のコードに示します。
<bindings>
<wsFederationHttpBinding>
<binding name="ServiceFed">
<security mode="Message">
<message issuedKeyType="SymmetricKey"
issuedTokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1">
<issuerMetadata address="http://localhost:8000/sts/mex">
<identity>
<certificateReference storeLocation="CurrentUser"
storeName="TrustedPeople"
x509FindType="FindBySubjectDistinguishedName"
findValue="CN=STS" />
</identity>
</issuerMetadata>
</message>
</security>
</binding>
</wsFederationHttpBinding>
</bindings>
security
のwsFederationHttpBinding
要素では、mode
値によって使用するセキュリティ モードが構成されます。 このサンプルでは、メッセージセキュリティが使用されているため、message
のwsFederationHttpBinding
要素がsecurity
のwsFederationHttpBinding
要素内で指定されています。
issuerMetadata
のwsFederationHttpBinding
要素内のmessage
のwsFederationHttpBinding
要素は、セキュリティ トークン サービスのメタデータを取得するために使用できるエンドポイントのアドレスと ID を指定します。
サービスの動作を次のコードに示します。
<behavior name="ServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata httpGetEnabled="true" />
<serviceCredentials>
<issuedTokenAuthentication>
<knownCertificates>
<add storeLocation="LocalMachine"
storeName="TrustedPeople"
x509FindType="FindBySubjectDistinguishedName"
findValue="CN=STS" />
</knownCertificates>
</issuedTokenAuthentication>
<serviceCertificate storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectDistinguishedName"
findValue="CN=localhost" />
</serviceCredentials>
</behavior>
issuedTokenAuthentication
要素内の serviceCredentials
要素を使用すると、認証時にクライアントが提示できるトークンに対する制約をサービスで指定できます。 この構成では、サブジェクト名が CN=STS である証明書によって署名されたトークンがサービスによって受け入れられることを指定します。
セキュリティ トークン サービスは、標準の wsHttpBinding を使用して単一のエンドポイントを公開します。 セキュリティ トークン サービスは、トークンに対するクライアントからの要求に応答し、クライアントが Windows アカウントを使用して認証を行う場合は、発行されたトークンの要求としてクライアントのユーザー名を含むトークンを発行します。 トークンの作成の一環として、セキュリティ トークン サービスは CN=STS 証明書に関連付けられている秘密キーを使用してトークンに署名します。 さらに、対称キーを作成し、CN=localhost 証明書に関連付けられている公開キーを使用して暗号化します。 トークンをクライアントに返す場合、セキュリティ トークン サービスは対称キーも返します。 クライアントは、発行されたトークンを電卓サービスに提示し、そのキーを使用してメッセージに署名することで対称キーを認識していることを証明します。
カスタム クライアント資格情報とトークン プロバイダー
次の手順では、発行されたトークンをキャッシュし、WCF と統合するカスタム トークン プロバイダーを開発する方法を示します。
カスタム トークン プロバイダーを開発するには
カスタム トークン プロバイダーを記述します。
このサンプルでは、キャッシュから取得したセキュリティ トークンを返すカスタム トークン プロバイダーを実装しています。
このタスクを実行するために、カスタム トークン プロバイダーは SecurityTokenProvider クラスを派生させ、 GetTokenCore メソッドをオーバーライドします。 このメソッドは、キャッシュからトークンを取得しようとします。または、キャッシュ内にトークンが見つからない場合は、基になるプロバイダーからトークンを取得し、そのトークンをキャッシュします。 どちらの場合も、メソッドは
SecurityToken
を返します。protected override SecurityToken GetTokenCore(TimeSpan timeout) { GenericXmlSecurityToken token; if (!this.cache.TryGetToken(target, issuer, out token)) { token = (GenericXmlSecurityToken) this.innerTokenProvider.GetToken(timeout); this.cache.AddToken(token, target, issuer); } return token; }
カスタム セキュリティ トークン マネージャーを記述します。
SecurityTokenManagerは、SecurityTokenProvider メソッドで渡される特定のSecurityTokenRequirementの
CreateSecurityTokenProvider
を作成するために使用されます。 セキュリティ トークン マネージャーは、トークン認証子とトークン シリアライザーの作成にも使用されますが、このサンプルでは扱いません。 このサンプルでは、カスタム セキュリティ トークン マネージャーは、 ClientCredentialsSecurityTokenManager クラスから継承し、渡されたトークン要件が発行されたトークンが要求されたことを示すときに、カスタム トークン プロバイダーを返すCreateSecurityTokenProvider
メソッドをオーバーライドします。class DurableIssuedTokenClientCredentialsTokenManager : ClientCredentialsSecurityTokenManager { IssuedTokenCache cache; public DurableIssuedTokenClientCredentialsTokenManager ( DurableIssuedTokenClientCredentials creds ): base(creds) { this.cache = creds.IssuedTokenCache; } public override SecurityTokenProvider CreateSecurityTokenProvider ( SecurityTokenRequirement tokenRequirement ) { if (IsIssuedSecurityTokenRequirement(tokenRequirement)) { return new DurableIssuedSecurityTokenProvider ((IssuedSecurityTokenProvider)base.CreateSecurityTokenProvider( tokenRequirement), this.cache); } else { return base.CreateSecurityTokenProvider(tokenRequirement); } } }
カスタム クライアント資格情報を書き込みます。
クライアント資格情報クラスは、クライアント プロキシ用に構成された資格情報を表すために使用され、トークン認証子、トークン プロバイダー、トークン シリアライザーを取得するために使用されるセキュリティ トークン マネージャーを作成します。
public class DurableIssuedTokenClientCredentials : ClientCredentials { IssuedTokenCache cache; public DurableIssuedTokenClientCredentials() : base() { } DurableIssuedTokenClientCredentials ( DurableIssuedTokenClientCredentials other) : base(other) { this.cache = other.cache; } public IssuedTokenCache IssuedTokenCache { get { return this.cache; } set { this.cache = value; } } protected override ClientCredentials CloneCore() { return new DurableIssuedTokenClientCredentials(this); } public override SecurityTokenManager CreateSecurityTokenManager() { return new DurableIssuedTokenClientCredentialsTokenManager ((DurableIssuedTokenClientCredentials)this.Clone()); } }
トークン キャッシュを実装します。 このサンプル実装では、特定のトークン キャッシュのコンシューマーがキャッシュと対話する抽象基本クラスを使用します。
public abstract class IssuedTokenCache { public abstract void AddToken ( GenericXmlSecurityToken token, EndpointAddress target, EndpointAddress issuer); public abstract bool TryGetToken(EndpointAddress target, EndpointAddress issuer, out GenericXmlSecurityToken cachedToken); } // Configure the client to use the custom client credential.
クライアントがカスタム クライアント資格情報を使用するために、サンプルは既定のクライアント資格情報クラスを削除し、新しいクライアント資格情報クラスを提供します。
clientFactory.Endpoint.Behaviors.Remove<ClientCredentials>(); DurableIssuedTokenClientCredentials durableCreds = new DurableIssuedTokenClientCredentials(); durableCreds.IssuedTokenCache = cache; durableCreds.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust; clientFactory.Endpoint.Behaviors.Add(durableCreds);
サンプルの実行
サンプルを実行するには、次の手順を参照してください。 サンプルを実行すると、セキュリティ トークンの要求が [セキュリティ トークン サービス] コンソール ウィンドウに表示されます。 操作の要求と応答は、クライアントおよびサービス コンソール ウィンドウに表示されます。 いずれかのコンソール ウィンドウで Enter キーを押して、アプリケーションをシャットダウンします。
Setup.cmd バッチファイル
このサンプルに含まれる Setup.cmd バッチ ファイルを使用すると、セルフホステッド アプリケーションを実行するために、関連する証明書を使用してサーバーとセキュリティ トークン サービスを構成できます。 バッチ ファイルは、CurrentUser/TrustedPeople 証明書ストアに両方の証明書を作成します。 最初の証明書は CN=STS というサブジェクト名を持ち、クライアントに発行するセキュリティ トークンに署名するためにセキュリティ トークン サービスによって使用されます。 2 番目の証明書は CN=localhost というサブジェクト名を持ち、セキュリティ トークン サービスによってシークレットを暗号化するために使用され、サービスで暗号化を解除できます。
サンプルを設定、ビルド、実行するには
Setup.cmd ファイルを実行して、必要な証明書を作成します。
ソリューションをビルドするには、「 Windows Communication Foundation サンプルのビルド」の手順に従います。 ソリューション内のすべてのプロジェクトがビルドされていることを確認します (Shared、RSTRSTR、Service、SecurityTokenService、および Client)。
Service.exe と SecurityTokenService.exe の両方が管理者特権で実行されていることを確認します。
Client.exeを実行します。
サンプルの実行後にクリーンアップするには
サンプルの実行が完了したら、samples フォルダーでCleanup.cmdを実行します。