このトピックでは、 SecurityToken クラスを使用してカスタム セキュリティ トークンを作成する方法と、それをカスタム セキュリティ トークン プロバイダーおよび認証子と統合する方法について説明します。 完全なコード例については、 カスタム トークン のサンプルを参照してください。
セキュリティ トークンは、基本的には、SOAP メッセージ内の送信者に関する要求を表すために Windows Communication Foundation (WCF) セキュリティ フレームワークによって使用される XML 要素です。 WCF セキュリティは、システム提供の認証モードにさまざまなトークンを提供します。 たとえば、 X509SecurityToken クラスで表される X.509 証明書セキュリティ トークンや、 UserNameSecurityToken クラスによって表される Username セキュリティ トークンなどがあります。
認証モードまたは資格情報が、指定された種類でサポートされていない場合があります。 その場合は、SOAP メッセージ内でカスタム資格情報の XML 表現を提供するカスタム セキュリティ トークンを作成する必要があります。
次の手順では、カスタム セキュリティ トークンを作成する方法と、それを WCF セキュリティ インフラストラクチャと統合する方法を示します。 このトピックでは、クライアントのクレジット カードに関する情報をサーバーに渡すために使用されるクレジット カード トークンを作成します。
カスタム資格情報とセキュリティ トークン マネージャーの詳細については、「 チュートリアル: カスタム クライアントとサービス資格情報の作成」を参照してください。
セキュリティ トークンを表すその他のクラスについては、 System.IdentityModel.Tokens 名前空間を参照してください。
プロシージャ
クライアント アプリケーションには、セキュリティ インフラストラクチャのクレジット カード情報を指定する方法が用意されている必要があります。 この情報は、カスタム クライアント資格情報クラスによってアプリケーションで使用できるようになります。 最初の手順では、カスタム クライアント資格情報のクレジット カード情報を表すクラスを作成します。
クライアント資格情報内のクレジット カード情報を表すクラスを作成するには
アプリケーションのクレジット カード情報を表す新しいクラスを定義します。 次の例では、クラスに
CreditCardInfo名前を付けます。アプリケーションがカスタム トークンに必要な情報を設定できるように、クラスに適切なプロパティを追加します。 この例では、クラスには、
CardNumber、CardIssuer、ExpirationDateの 3 つのプロパティがあります。public class CreditCardInfo { string cardNumber; string cardIssuer; DateTime expirationDate; public CreditCardInfo(string cardNumber, string cardIssuer, DateTime expirationDate) { this.cardNumber = cardNumber; this.cardIssuer = cardIssuer; this.expirationDate = expirationDate; } public string CardNumber { get { return this.cardNumber; } } public string CardIssuer { get { return this.cardIssuer; } } public DateTime ExpirationDate { get { return this.expirationDate; } } }Public Class CreditCardInfo Private _cardNumber As String Private _cardIssuer As String Private _expirationDate As DateTime Public Sub New(ByVal cardNumber As String, ByVal cardIssuer As String, _ ByVal expirationDate As DateTime) Me._cardNumber = cardNumber Me._cardIssuer = cardIssuer Me._expirationDate = expirationDate End Sub Public ReadOnly Property CardNumber() As String Get Return Me._cardNumber End Get End Property Public ReadOnly Property CardIssuer() As String Get Return Me._cardIssuer End Get End Property Public ReadOnly Property ExpirationDate() As DateTime Get Return Me._expirationDate End Get End Property End Class
次に、カスタム セキュリティ トークンを表すクラスを作成する必要があります。 このクラスは、セキュリティ トークン プロバイダー、認証子、およびシリアライザー クラスによって、WCF セキュリティ インフラストラクチャとの間でセキュリティ トークンに関する情報を渡すために使用されます。
カスタム セキュリティ トークン クラスを作成するには
SecurityToken クラスから派生する新しいクラスを定義します。 この例では、
CreditCardTokenという名前のクラスを作成します。Id プロパティをオーバーライドします。 このプロパティは、SOAP メッセージ内の他の要素からセキュリティ トークン XML 表現を指すために使用されるセキュリティ トークンのローカル識別子を取得するために使用されます。 この例では、トークン識別子をコンストラクター パラメーターとして渡すか、セキュリティ トークン インスタンスが作成されるたびに新しいランダム識別子を生成できます。
SecurityKeys プロパティを実装します。 このプロパティは、セキュリティ トークン インスタンスが表すセキュリティ キーのコレクションを返します。 このようなキーは、WCF が SOAP メッセージの一部に署名または暗号化するために使用できます。 この例では、クレジット カードのセキュリティ トークンにセキュリティ キーを含めることはできません。そのため、実装は常に空のコレクションを返します。
ValidFromプロパティとValidToプロパティをオーバーライドします。 これらのプロパティは、セキュリティ トークン インスタンスの有効性を判断するために WCF によって使用されます。 この例では、クレジット カード セキュリティ トークンには有効期限のみがあるため、
ValidFromプロパティはインスタンスの作成日時を表す DateTime を返します。class CreditCardToken : SecurityToken { CreditCardInfo cardInfo; DateTime effectiveTime = DateTime.UtcNow; string id; ReadOnlyCollection<SecurityKey> securityKeys; public CreditCardToken(CreditCardInfo cardInfo) : this(cardInfo, Guid.NewGuid().ToString()) { } public CreditCardToken(CreditCardInfo cardInfo, string id) { if (cardInfo == null) { throw new ArgumentNullException("cardInfo"); } if (id == null) { throw new ArgumentNullException("id"); } this.cardInfo = cardInfo; this.id = id; // The credit card token is not capable of any cryptography. this.securityKeys = new ReadOnlyCollection<SecurityKey>(new List<SecurityKey>()); } public CreditCardInfo CardInfo { get { return this.cardInfo; } } public override ReadOnlyCollection<SecurityKey> SecurityKeys { get { return this.securityKeys; } } public override DateTime ValidFrom { get { return this.effectiveTime; } } public override DateTime ValidTo { get { return this.cardInfo.ExpirationDate; } } public override string Id { get { return this.id; } } }Friend Class CreditCardToken Inherits SecurityToken Private _cardInfo As CreditCardInfo Private _effectiveTime As DateTime = DateTime.UtcNow Private _id As String Private _securityKeys As ReadOnlyCollection(Of SecurityKey) Public Sub New(ByVal cardInfo As CreditCardInfo) Me.New(cardInfo, Guid.NewGuid().ToString()) End Sub Public Sub New(ByVal cardInfo As CreditCardInfo, _ ByVal id As String) If cardInfo Is Nothing Then Throw New ArgumentNullException("cardInfo") End If If id Is Nothing Then Throw New ArgumentNullException("id") End If Me._cardInfo = cardInfo Me._id = id ' The credit card token is not capable of any cryptography. Me._securityKeys = New ReadOnlyCollection(Of SecurityKey)(New List(Of SecurityKey)()) End Sub Public ReadOnly Property CardInfo() As CreditCardInfo Get Return Me._cardInfo End Get End Property Public Overrides ReadOnly Property SecurityKeys() As ReadOnlyCollection(Of SecurityKey) Get Return Me._securityKeys End Get End Property Public Overrides ReadOnly Property ValidFrom() As DateTime Get Return Me._effectiveTime End Get End Property Public Overrides ReadOnly Property ValidTo() As DateTime Get Return Me._cardInfo.ExpirationDate End Get End Property Public Overrides ReadOnly Property Id() As String Get Return Me._id End Get End Property End Class
新しいセキュリティ トークンの種類を作成するときは、 SecurityTokenParameters クラスの実装が必要です。 この実装は、新しいトークンの種類を表すために、セキュリティ バインディング要素の構成で使用されます。 セキュリティ トークン パラメーター クラスは、メッセージの処理時に実際のセキュリティ トークン インスタンスと照合するために使用されるテンプレートとして機能します。 このテンプレートには、アプリケーションが使用または認証するためにセキュリティ トークンが一致する必要がある条件を指定するために使用できる追加のプロパティが用意されています。 次の例では、追加のプロパティは追加されないため、WCF インフラストラクチャが使用または検証するセキュリティ トークン インスタンスを検索するときに、セキュリティ トークンの種類のみが照合されます。
カスタム セキュリティ トークン パラメーター クラスを作成するには
SecurityTokenParameters クラスから派生する新しいクラスを定義します。
CloneCore メソッドを実装します。 クラスで定義されているすべての内部フィールド (存在する場合) をコピーします。 この例では、追加のフィールドは定義しません。
SupportsClientAuthentication読み取り専用プロパティを実装します。 このプロパティは、このクラスで表されるセキュリティ トークンの種類を使用してサービスに対するクライアントの認証を行うことができる場合、
trueを返します。 この例では、クレジット カード セキュリティ トークンを使用して、サービスに対するクライアントの認証を行うことができます。SupportsServerAuthentication読み取り専用プロパティを実装します。 このプロパティは、このクラスで表されるセキュリティ トークンの種類を使用してクライアントに対するサービスを認証できる場合、
trueを返します。 この例では、クレジット カード セキュリティ トークンを使用してクライアントに対するサービスを認証することはできません。SupportsClientWindowsIdentity読み取り専用プロパティを実装します。 このプロパティは、このクラスで表されるセキュリティ トークンの種類を Windows アカウントにマップできる場合、
trueを返します。 その場合、認証結果は WindowsIdentity クラス インスタンスによって表されます。 この例では、トークンを Windows アカウントにマップできません。CreateKeyIdentifierClause(SecurityToken, SecurityTokenReferenceStyle) メソッドを実装します。 このメソッドは、このセキュリティ トークン パラメーター クラスで表されるセキュリティ トークン インスタンスへの参照が必要な場合に、WCF セキュリティ フレームワークによって呼び出されます。 要求される参照の型を指定する実際のセキュリティ トークン インスタンスと SecurityTokenReferenceStyle の両方が、引数としてこのメソッドに渡されます。 この例では、クレジット カード セキュリティ トークンでは内部参照のみがサポートされています。 SecurityToken クラスには内部参照を作成する機能があるため、実装には追加のコードは必要ありません。
InitializeSecurityTokenRequirement(SecurityTokenRequirement) メソッドを実装します。 このメソッドは、セキュリティ トークン パラメーター クラス インスタンスを SecurityTokenRequirement クラスのインスタンスに変換するために WCF によって呼び出されます。 結果は、セキュリティ トークン プロバイダーが適切なセキュリティ トークン インスタンスを作成するために使用されます。
public class CreditCardTokenParameters : SecurityTokenParameters { public CreditCardTokenParameters() { } protected CreditCardTokenParameters(CreditCardTokenParameters other) : base(other) { } protected override SecurityTokenParameters CloneCore() { return new CreditCardTokenParameters(this); } protected override void InitializeSecurityTokenRequirement(SecurityTokenRequirement requirement) { requirement.TokenType = Constants.CreditCardTokenType; return; } // A credit card token has no cryptography, no windows identity, and supports only client authentication. protected override bool HasAsymmetricKey { get { return false; } } protected override bool SupportsClientAuthentication { get { return true; } } protected override bool SupportsClientWindowsIdentity { get { return false; } } protected override bool SupportsServerAuthentication { get { return false; } } protected override SecurityKeyIdentifierClause CreateKeyIdentifierClause(SecurityToken token, SecurityTokenReferenceStyle referenceStyle) { if (referenceStyle == SecurityTokenReferenceStyle.Internal) { return token.CreateKeyIdentifierClause<LocalIdKeyIdentifierClause>(); } else { throw new NotSupportedException("External references are not supported for credit card tokens"); } } }Public Class CreditCardTokenParameters Inherits SecurityTokenParameters Public Sub New() End Sub Protected Sub New(ByVal other As CreditCardTokenParameters) MyBase.New(other) End Sub Protected Overrides Function CloneCore() As SecurityTokenParameters Return New CreditCardTokenParameters(Me) End Function Protected Overrides Sub InitializeSecurityTokenRequirement(ByVal requirement As SecurityTokenRequirement) requirement.TokenType = Constants.CreditCardTokenType Return End Sub ' A credit card token has no cryptography, no windows identity, and supports only client authentication. Protected Overrides ReadOnly Property HasAsymmetricKey() As Boolean Get Return False End Get End Property Protected Overrides ReadOnly Property SupportsClientAuthentication() As Boolean Get Return True End Get End Property Protected Overrides ReadOnly Property SupportsClientWindowsIdentity() As Boolean Get Return False End Get End Property Protected Overrides ReadOnly Property SupportsServerAuthentication() As Boolean Get Return False End Get End Property Protected Overrides Function CreateKeyIdentifierClause(ByVal token As SecurityToken, _ ByVal referenceStyle As SecurityTokenReferenceStyle) As SecurityKeyIdentifierClause If referenceStyle = SecurityTokenReferenceStyle.Internal Then Return token.CreateKeyIdentifierClause(Of LocalIdKeyIdentifierClause)() Else Throw New NotSupportedException("External references are not supported for credit card tokens") End If End Function End Class
セキュリティ トークンは SOAP メッセージ内で送信されます。これには、メモリ内のセキュリティ トークン表現とネットワーク上の表現との間の変換メカニズムが必要です。 WCF では、セキュリティ トークン シリアライザーを使用してこのタスクを実行します。 すべてのカスタム トークンには、SOAP メッセージからカスタム セキュリティ トークンをシリアル化および逆シリアル化できるカスタム セキュリティ トークン シリアライザーが必要です。
注
派生キーは既定で有効になっています。 カスタム セキュリティ トークンを作成し、それをプライマリ トークンとして使用すると、WCF はそこからキーを派生させます。 その間、カスタム セキュリティ トークン シリアライザーを呼び出して、SecurityKeyIdentifierClauseをワイヤにシリアル化しながら、カスタム セキュリティ トークンのDerivedKeyTokenを書き込みます。 受信側では、トークンをネットワークから逆シリアル化する際に、DerivedKeyToken シリアライザーは自分の下に最上位の子としてSecurityTokenReference 要素があることを期待します。 カスタム セキュリティ トークン シリアライザーが句型のシリアル化中に SecurityTokenReference 要素を追加しなかった場合は、例外がスローされます。
カスタム セキュリティ トークン シリアライザーを作成するには
WSSecurityTokenSerializer クラスから派生する新しいクラスを定義します。
CanReadTokenCore(XmlReader)メソッドをオーバーライドします。このメソッドは、XML ストリームの読み取りにXmlReaderに依存します。 このメソッドは、シリアライザーの実装が現在の要素に基づいてセキュリティ トークンを逆シリアル化できる場合、
trueを返します。 この例では、このメソッドは、XML リーダーの現在の XML 要素が正しい要素名と名前空間を持っているかどうかを確認します。 そうでない場合は、このメソッドの基底クラス実装を呼び出して XML 要素を処理します。ReadTokenCore(XmlReader, SecurityTokenResolver) メソッドをオーバーライドします。 このメソッドは、セキュリティ トークンの XML コンテンツを読み取り、それに適したメモリ内表現を構築します。 渡された XML リーダーが存在する XML 要素を認識しない場合は、基底クラスの実装を呼び出して、システム提供のトークン型を処理します。
CanWriteTokenCore(SecurityToken) メソッドをオーバーライドします。 このメソッドは、メモリ内トークン表現 (引数として渡される) を XML 表現に変換できる場合、
trueを返します。 変換できない場合は、基底クラスの実装を呼び出します。WriteTokenCore(XmlWriter, SecurityToken) メソッドをオーバーライドします。 このメソッドは、インメモリ セキュリティ トークン表現を XML 表現に変換します。 メソッドが変換できない場合は、基底クラスの実装を呼び出します。
public class CreditCardSecurityTokenSerializer : WSSecurityTokenSerializer { public CreditCardSecurityTokenSerializer(SecurityTokenVersion version) : base() { } protected override bool CanReadTokenCore(XmlReader reader) { XmlDictionaryReader localReader = XmlDictionaryReader.CreateDictionaryReader(reader); if (reader == null) { throw new ArgumentNullException("reader"); } if (reader.IsStartElement(Constants.CreditCardTokenName, Constants.CreditCardTokenNamespace)) { return true; } return base.CanReadTokenCore(reader); } protected override SecurityToken ReadTokenCore(XmlReader reader, SecurityTokenResolver tokenResolver) { if (reader == null) { throw new ArgumentNullException("reader"); } if (reader.IsStartElement(Constants.CreditCardTokenName, Constants.CreditCardTokenNamespace)) { string id = reader.GetAttribute(Constants.Id, Constants.WsUtilityNamespace); reader.ReadStartElement(); // Read the credit card number. string creditCardNumber = reader.ReadElementString(Constants.CreditCardNumberElementName, Constants.CreditCardTokenNamespace); // Read the expiration date. string expirationTimeString = reader.ReadElementString(Constants.CreditCardExpirationElementName, Constants.CreditCardTokenNamespace); DateTime expirationTime = XmlConvert.ToDateTime(expirationTimeString, XmlDateTimeSerializationMode.Utc); // Read the issuer of the credit card. string creditCardIssuer = reader.ReadElementString(Constants.CreditCardIssuerElementName, Constants.CreditCardTokenNamespace); reader.ReadEndElement(); CreditCardInfo cardInfo = new CreditCardInfo(creditCardNumber, creditCardIssuer, expirationTime); return new CreditCardToken(cardInfo, id); } else { return WSSecurityTokenSerializer.DefaultInstance.ReadToken(reader, tokenResolver); } } protected override bool CanWriteTokenCore(SecurityToken token) { if (token is CreditCardToken) { return true; } else { return base.CanWriteTokenCore(token); } } protected override void WriteTokenCore(XmlWriter writer, SecurityToken token) { if (writer == null) { throw new ArgumentNullException("writer"); } if (token == null) { throw new ArgumentNullException("token"); } CreditCardToken c = token as CreditCardToken; if (c != null) { writer.WriteStartElement(Constants.CreditCardTokenPrefix, Constants.CreditCardTokenName, Constants.CreditCardTokenNamespace); writer.WriteAttributeString(Constants.WsUtilityPrefix, Constants.Id, Constants.WsUtilityNamespace, token.Id); writer.WriteElementString(Constants.CreditCardNumberElementName, Constants.CreditCardTokenNamespace, c.CardInfo.CardNumber); writer.WriteElementString(Constants.CreditCardExpirationElementName, Constants.CreditCardTokenNamespace, XmlConvert.ToString(c.CardInfo.ExpirationDate, XmlDateTimeSerializationMode.Utc)); writer.WriteElementString(Constants.CreditCardIssuerElementName, Constants.CreditCardTokenNamespace, c.CardInfo.CardIssuer); writer.WriteEndElement(); writer.Flush(); } else { base.WriteTokenCore(writer, token); } } }Public Class CreditCardSecurityTokenSerializer Inherits WSSecurityTokenSerializer Public Sub New(ByVal version As SecurityTokenVersion) MyBase.New() End Sub Protected Overrides Function CanReadTokenCore(ByVal reader As XmlReader) As Boolean Dim localReader = XmlDictionaryReader.CreateDictionaryReader(reader) If reader Is Nothing Then Throw New ArgumentNullException("reader") End If If reader.IsStartElement(Constants.CreditCardTokenName, _ Constants.CreditCardTokenNamespace) Then Return True End If Return MyBase.CanReadTokenCore(reader) End Function Protected Overrides Function ReadTokenCore(ByVal reader As XmlReader, _ ByVal tokenResolver As SecurityTokenResolver) As SecurityToken If reader Is Nothing Then Throw New ArgumentNullException("reader") End If If reader.IsStartElement(Constants.CreditCardTokenName, _ Constants.CreditCardTokenNamespace) Then Dim id = reader.GetAttribute(Constants.Id, _ Constants.WsUtilityNamespace) reader.ReadStartElement() ' Read the credit card number. Dim creditCardNumber = reader.ReadElementString(Constants.CreditCardNumberElementName, _ Constants.CreditCardTokenNamespace) ' Read the expiration date. Dim expirationTimeString = reader.ReadElementString(Constants.CreditCardExpirationElementName, _ Constants.CreditCardTokenNamespace) Dim expirationTime As DateTime = XmlConvert.ToDateTime(expirationTimeString, _ XmlDateTimeSerializationMode.Utc) ' Read the issuer of the credit card. Dim creditCardIssuer = reader.ReadElementString(Constants.CreditCardIssuerElementName, _ Constants.CreditCardTokenNamespace) reader.ReadEndElement() Dim cardInfo As New CreditCardInfo(creditCardNumber, _ creditCardIssuer, _ expirationTime) Return New CreditCardToken(cardInfo, id) Else Return WSSecurityTokenSerializer.DefaultInstance.ReadToken(reader, _ tokenResolver) End If End Function Protected Overrides Function CanWriteTokenCore(ByVal token As SecurityToken) As Boolean If TypeOf token Is CreditCardToken Then Return True Else Return MyBase.CanWriteTokenCore(token) End If End Function Protected Overrides Sub WriteTokenCore(ByVal writer As XmlWriter, _ ByVal token As SecurityToken) If writer Is Nothing Then Throw New ArgumentNullException("writer") End If If token Is Nothing Then Throw New ArgumentNullException("token") End If Dim c = TryCast(token, CreditCardToken) If c IsNot Nothing Then With writer .WriteStartElement(Constants.CreditCardTokenPrefix, _ Constants.CreditCardTokenName, _ Constants.CreditCardTokenNamespace) .WriteAttributeString(Constants.WsUtilityPrefix, _ Constants.Id, _ Constants.WsUtilityNamespace, _ token.Id) .WriteElementString(Constants.CreditCardNumberElementName, _ Constants.CreditCardTokenNamespace, _ c.CardInfo.CardNumber) .WriteElementString(Constants.CreditCardExpirationElementName, _ Constants.CreditCardTokenNamespace, _ XmlConvert.ToString(c.CardInfo.ExpirationDate, _ XmlDateTimeSerializationMode.Utc)) .WriteElementString(Constants.CreditCardIssuerElementName, _ Constants.CreditCardTokenNamespace, _ c.CardInfo.CardIssuer) .WriteEndElement() .Flush() End With Else MyBase.WriteTokenCore(writer, token) End If End Sub End Class
前の 4 つの手順を完了したら、カスタム セキュリティ トークンをセキュリティ トークン プロバイダー、認証システム、マネージャー、およびクライアントとサービスの資格情報と統合します。
カスタム セキュリティ トークンをセキュリティ トークン プロバイダーと統合するには
セキュリティ トークン プロバイダーは、トークンのインスタンスを作成、変更 (必要な場合) して返します。 カスタム セキュリティ トークンのカスタム プロバイダーを作成するには、 SecurityTokenProvider クラスから継承するクラスを作成します。 次の例では、 GetTokenCore メソッドをオーバーライドして、
CreditCardTokenのインスタンスを返します。 カスタム セキュリティ トークン プロバイダーの詳細については、「方法: カスタム セキュリティ トークン プロバイダーを作成する」を参照してください。class CreditCardTokenProvider : SecurityTokenProvider { CreditCardInfo creditCardInfo; public CreditCardTokenProvider(CreditCardInfo creditCardInfo) : base() { if (creditCardInfo == null) { throw new ArgumentNullException("creditCardInfo"); } this.creditCardInfo = creditCardInfo; } protected override SecurityToken GetTokenCore(TimeSpan timeout) { SecurityToken result = new CreditCardToken(this.creditCardInfo); return result; } }Friend Class CreditCardTokenProvider Inherits SecurityTokenProvider Private creditCardInfo As CreditCardInfo Public Sub New(ByVal creditCardInfo As CreditCardInfo) MyBase.New() If creditCardInfo Is Nothing Then Throw New ArgumentNullException("creditCardInfo") End If Me.creditCardInfo = creditCardInfo End Sub Protected Overrides Function GetTokenCore(ByVal timeout As TimeSpan) As SecurityToken Return TryCast(New CreditCardToken(Me.creditCardInfo), SecurityToken) End Function End Class
カスタム セキュリティ トークンをセキュリティ トークン認証子と統合するには
セキュリティ トークン認証子は、メッセージからセキュリティ トークンが抽出されるときに、セキュリティ トークンの内容を検証します。 カスタム セキュリティ トークンのカスタム認証子を作成するには、 SecurityTokenAuthenticator クラスから継承するクラスを作成します。 次の例では、 ValidateTokenCore メソッドをオーバーライドします。 カスタム セキュリティ トークン認証システムの詳細については、「方法: カスタム セキュリティ トークン認証システムを作成する」を参照してください。
class CreditCardTokenAuthenticator : SecurityTokenAuthenticator { string creditCardsFile; public CreditCardTokenAuthenticator(string creditCardsFile) { this.creditCardsFile = creditCardsFile; } protected override bool CanValidateTokenCore(SecurityToken token) { return (token is CreditCardToken); } protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateTokenCore(SecurityToken token) { CreditCardToken creditCardToken = token as CreditCardToken; if (creditCardToken.CardInfo.ExpirationDate < DateTime.UtcNow) { throw new SecurityTokenValidationException("The credit card has expired"); } if (!IsCardNumberAndExpirationValid(creditCardToken.CardInfo)) { throw new SecurityTokenValidationException("Unknown or invalid credit card"); } // The credit card token has only 1 claim: the card number. The issuer for the claim is the // credit card issuer. DefaultClaimSet cardIssuerClaimSet = new DefaultClaimSet(new Claim(ClaimTypes.Name, creditCardToken.CardInfo.CardIssuer, Rights.PossessProperty)); DefaultClaimSet cardClaimSet = new DefaultClaimSet(cardIssuerClaimSet, new Claim(Constants.CreditCardNumberClaim, creditCardToken.CardInfo.CardNumber, Rights.PossessProperty)); List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1); policies.Add(new CreditCardTokenAuthorizationPolicy(cardClaimSet)); return policies.AsReadOnly(); } // This helper method checks whether a given credit card entry is present in the user database. private bool IsCardNumberAndExpirationValid(CreditCardInfo cardInfo) { try { using (StreamReader myStreamReader = new StreamReader(this.creditCardsFile)) { string line = ""; while ((line = myStreamReader.ReadLine()) != null) { string[] splitEntry = line.Split('#'); if (splitEntry[0] == cardInfo.CardNumber) { string expirationDateString = splitEntry[1].Trim(); DateTime expirationDateOnFile = DateTime.Parse(expirationDateString, System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.AdjustToUniversal); if (cardInfo.ExpirationDate == expirationDateOnFile) { string issuer = splitEntry[2]; return issuer.Equals(cardInfo.CardIssuer, StringComparison.InvariantCultureIgnoreCase); } else { return false; } } } return false; } } catch (Exception e) { throw new Exception("BookStoreService: Error while retrieving credit card information from User DB " + e.ToString()); } } }Friend Class CreditCardTokenAuthenticator Inherits SecurityTokenAuthenticator Private creditCardsFile As String Public Sub New(ByVal creditCardsFile As String) Me.creditCardsFile = creditCardsFile End Sub Protected Overrides Function CanValidateTokenCore(ByVal token As SecurityToken) As Boolean Return (TypeOf token Is CreditCardToken) End Function Protected Overrides Function ValidateTokenCore(ByVal token As SecurityToken) As ReadOnlyCollection(Of IAuthorizationPolicy) Dim creditCardToken = TryCast(token, CreditCardToken) If creditCardToken.CardInfo.ExpirationDate < DateTime.UtcNow Then Throw New SecurityTokenValidationException("The credit card has expired") End If If Not IsCardNumberAndExpirationValid(creditCardToken.CardInfo) Then Throw New SecurityTokenValidationException("Unknown or invalid credit card") End If ' The credit card token has only 1 claim: the card number. The issuer for the claim is the ' credit card issuer. Dim cardIssuerClaimSet As New DefaultClaimSet(New Claim(ClaimTypes.Name, _ creditCardToken.CardInfo.CardIssuer, _ Rights.PossessProperty)) Dim cardClaimSet As New DefaultClaimSet(cardIssuerClaimSet, _ New Claim(Constants.CreditCardNumberClaim, _ creditCardToken.CardInfo.CardNumber, _ Rights.PossessProperty)) Dim policies As New List(Of IAuthorizationPolicy)(1) policies.Add(New CreditCardTokenAuthorizationPolicy(cardClaimSet)) Return policies.AsReadOnly() End Function ' This helper method checks whether a given credit card entry is present in the user database. Private Function IsCardNumberAndExpirationValid(ByVal cardInfo As CreditCardInfo) As Boolean Try Using myStreamReader As New StreamReader(Me.creditCardsFile) Dim line = String.Empty line = myStreamReader.ReadLine() Do While line IsNot Nothing Dim splitEntry() = line.Split("#"c) If splitEntry(0) = cardInfo.CardNumber Then Dim expirationDateString = splitEntry(1).Trim() Dim expirationDateOnFile As DateTime = DateTime.Parse(expirationDateString, _ System.Globalization.DateTimeFormatInfo.InvariantInfo, _ System.Globalization.DateTimeStyles.AdjustToUniversal) If cardInfo.ExpirationDate = expirationDateOnFile Then Dim issuer = splitEntry(2) Return issuer.Equals(cardInfo.CardIssuer, _ StringComparison.InvariantCultureIgnoreCase) Else Return False End If End If line = myStreamReader.ReadLine() Loop Return False End Using Catch e As Exception Throw New Exception("BookStoreService: Error while retrieving credit card information from User DB " & e.ToString()) End Try End Function End Classpublic class CreditCardTokenAuthorizationPolicy : IAuthorizationPolicy { string id; ClaimSet issuer; IEnumerable<ClaimSet> issuedClaimSets; public CreditCardTokenAuthorizationPolicy(ClaimSet issuedClaims) { if (issuedClaims == null) throw new ArgumentNullException("issuedClaims"); this.issuer = issuedClaims.Issuer; this.issuedClaimSets = new ClaimSet[] { issuedClaims }; this.id = Guid.NewGuid().ToString(); } public ClaimSet Issuer { get { return this.issuer; } } public string Id { get { return this.id; } } public bool Evaluate(EvaluationContext context, ref object state) { foreach (ClaimSet issuance in this.issuedClaimSets) { context.AddClaimSet(this, issuance); } return true; } }Public Class CreditCardTokenAuthorizationPolicy Implements IAuthorizationPolicy Private _id As String Private _issuer As ClaimSet Private _issuedClaimSets As IEnumerable(Of ClaimSet) Public Sub New(ByVal issuedClaims As ClaimSet) If issuedClaims Is Nothing Then Throw New ArgumentNullException("issuedClaims") End If Me._issuer = issuedClaims.Issuer Me._issuedClaimSets = New ClaimSet() {issuedClaims} Me._id = Guid.NewGuid().ToString() End Sub Public ReadOnly Property Issuer() As ClaimSet Implements IAuthorizationPolicy.Issuer Get Return Me._issuer End Get End Property Public ReadOnly Property Id() As String Implements System.IdentityModel.Policy.IAuthorizationComponent.Id Get Return Me._id End Get End Property Public Function Evaluate(ByVal context As EvaluationContext, _ ByRef state As Object) As Boolean Implements IAuthorizationPolicy.Evaluate For Each issuance In Me._issuedClaimSets context.AddClaimSet(Me, issuance) Next issuance Return True End Function End Class
カスタム セキュリティ トークンをセキュリティ トークン マネージャーと統合するには
セキュリティ トークン マネージャーは、適切なトークン プロバイダー、セキュリティ認証子、およびトークン シリアライザー インスタンスを作成します。 カスタム トークン マネージャーを作成するには、 ClientCredentialsSecurityTokenManager クラスから継承するクラスを作成します。 クラスの主なメソッドは、 SecurityTokenRequirement を使用して、適切なプロバイダーとクライアントまたはサービスの資格情報を作成します。 カスタム セキュリティ トークン マネージャーの詳細については、「 チュートリアル: カスタム クライアントとサービス資格情報の作成」を参照してください。
public class CreditCardClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager { CreditCardClientCredentials creditCardClientCredentials; public CreditCardClientCredentialsSecurityTokenManager(CreditCardClientCredentials creditCardClientCredentials) : base(creditCardClientCredentials) { this.creditCardClientCredentials = creditCardClientCredentials; } public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) { if (tokenRequirement.TokenType == Constants.CreditCardTokenType) { // Handle this token for Custom. return new CreditCardTokenProvider(this.creditCardClientCredentials.CreditCardInfo); } else if (tokenRequirement is InitiatorServiceModelSecurityTokenRequirement) { // Return server certificate. if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate) { return new X509SecurityTokenProvider(creditCardClientCredentials.ServiceCertificate.DefaultCertificate); } } return base.CreateSecurityTokenProvider(tokenRequirement); } public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) { return new CreditCardSecurityTokenSerializer(version); } }Public Class CreditCardClientCredentialsSecurityTokenManager Inherits ClientCredentialsSecurityTokenManager Private creditCardClientCredentials As CreditCardClientCredentials Public Sub New(ByVal creditCardClientCredentials As CreditCardClientCredentials) MyBase.New(creditCardClientCredentials) Me.creditCardClientCredentials = creditCardClientCredentials End Sub Public Overrides Function CreateSecurityTokenProvider(ByVal tokenRequirement As SecurityTokenRequirement) As SecurityTokenProvider If tokenRequirement.TokenType = Constants.CreditCardTokenType Then ' Handle this token for Custom. Return New CreditCardTokenProvider(Me.creditCardClientCredentials.CreditCardInfo) ElseIf TypeOf tokenRequirement Is InitiatorServiceModelSecurityTokenRequirement Then ' Return server certificate. If tokenRequirement.TokenType = SecurityTokenTypes.X509Certificate Then Return New X509SecurityTokenProvider(creditCardClientCredentials.ServiceCertificate.DefaultCertificate) End If End If Return MyBase.CreateSecurityTokenProvider(tokenRequirement) End Function Public Overloads Overrides Function CreateSecurityTokenSerializer(ByVal version As SecurityTokenVersion) As SecurityTokenSerializer Return New CreditCardSecurityTokenSerializer(version) End Function End Classpublic class CreditCardServiceCredentialsSecurityTokenManager : ServiceCredentialsSecurityTokenManager { CreditCardServiceCredentials creditCardServiceCredentials; public CreditCardServiceCredentialsSecurityTokenManager(CreditCardServiceCredentials creditCardServiceCredentials) : base(creditCardServiceCredentials) { this.creditCardServiceCredentials = creditCardServiceCredentials; } public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) { if (tokenRequirement.TokenType == Constants.CreditCardTokenType) { outOfBandTokenResolver = null; return new CreditCardTokenAuthenticator(creditCardServiceCredentials.CreditCardDataFile); } return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver); } public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) { return new CreditCardSecurityTokenSerializer(version); } }Public Class CreditCardServiceCredentialsSecurityTokenManager Inherits ServiceCredentialsSecurityTokenManager Private creditCardServiceCredentials As CreditCardServiceCredentials Public Sub New(ByVal creditCardServiceCredentials As CreditCardServiceCredentials) MyBase.New(creditCardServiceCredentials) Me.creditCardServiceCredentials = creditCardServiceCredentials End Sub Public Overrides Function CreateSecurityTokenAuthenticator(ByVal tokenRequirement As SecurityTokenRequirement, _ <System.Runtime.InteropServices.Out()> ByRef outOfBandTokenResolver As SecurityTokenResolver) As SecurityTokenAuthenticator If tokenRequirement.TokenType = Constants.CreditCardTokenType Then outOfBandTokenResolver = Nothing Return New CreditCardTokenAuthenticator(creditCardServiceCredentials.CreditCardDataFile) End If Return MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, outOfBandTokenResolver) End Function Public Overrides Function CreateSecurityTokenSerializer(ByVal version As SecurityTokenVersion) As SecurityTokenSerializer Return New CreditCardSecurityTokenSerializer(version) End Function End Class
カスタム セキュリティ トークンをカスタム クライアントとサービスの資格情報と統合するには
カスタム セキュリティ トークンのコンテンツを提供および認証するために以前に作成されたカスタム セキュリティ トークン インフラストラクチャで使用されるカスタム トークン情報を指定できるように、アプリケーションの API を提供するために、カスタム クライアントとサービスの資格情報を追加する必要があります。 次のサンプルは、これを行う方法を示しています。 カスタム クライアントとサービスの資格情報の詳細については、「 チュートリアル: カスタム クライアントとサービス資格情報の作成」を参照してください。
public class CreditCardClientCredentials : ClientCredentials { CreditCardInfo creditCardInfo; public CreditCardClientCredentials(CreditCardInfo creditCardInfo) : base() { if (creditCardInfo == null) { throw new ArgumentNullException("creditCardInfo"); } this.creditCardInfo = creditCardInfo; } public CreditCardInfo CreditCardInfo { get { return this.creditCardInfo; } } protected override ClientCredentials CloneCore() { return new CreditCardClientCredentials(this.creditCardInfo); } public override SecurityTokenManager CreateSecurityTokenManager() { return new CreditCardClientCredentialsSecurityTokenManager(this); } }Public Class CreditCardClientCredentials Inherits ClientCredentials Private _creditCardInfo As CreditCardInfo Public Sub New(ByVal creditCardInfo As CreditCardInfo) MyBase.New() If creditCardInfo Is Nothing Then Throw New ArgumentNullException("creditCardInfo") End If Me._creditCardInfo = creditCardInfo End Sub Public ReadOnly Property CreditCardInfo() As CreditCardInfo Get Return Me._creditCardInfo End Get End Property Protected Overrides Function CloneCore() As ClientCredentials Return New CreditCardClientCredentials(Me._creditCardInfo) End Function Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager Return New CreditCardClientCredentialsSecurityTokenManager(Me) End Function End Classpublic class CreditCardServiceCredentials : ServiceCredentials { string creditCardFile; public CreditCardServiceCredentials(string creditCardFile) : base() { if (creditCardFile == null) { throw new ArgumentNullException("creditCardFile"); } this.creditCardFile = creditCardFile; } public string CreditCardDataFile { get { return this.creditCardFile; } } protected override ServiceCredentials CloneCore() { return new CreditCardServiceCredentials(this.creditCardFile); } public override SecurityTokenManager CreateSecurityTokenManager() { return new CreditCardServiceCredentialsSecurityTokenManager(this); } }Public Class CreditCardServiceCredentials Inherits ServiceCredentials Private creditCardFile As String Public Sub New(ByVal creditCardFile As String) MyBase.New() If creditCardFile Is Nothing Then Throw New ArgumentNullException("creditCardFile") End If Me.creditCardFile = creditCardFile End Sub Public ReadOnly Property CreditCardDataFile() As String Get Return Me.creditCardFile End Get End Property Protected Overrides Function CloneCore() As ServiceCredentials Return New CreditCardServiceCredentials(Me.creditCardFile) End Function Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager Return New CreditCardServiceCredentialsSecurityTokenManager(Me) End Function End Class
前に作成したカスタム セキュリティ トークン パラメーター クラスは、サービスとの通信時にカスタム セキュリティ トークンを使用する必要があることを WCF セキュリティ フレームワークに通知するために使用されます。 次の手順は、これを行う方法を示しています。
カスタム セキュリティ トークンをバインドと統合するには
カスタム セキュリティ トークン パラメーター クラスは、 SecurityBindingElement クラスで公開されているトークン パラメーター コレクションのいずれかで指定する必要があります。 次の例では、
SignedEncryptedによって返されるコレクションを使用します。 このコードでは、クライアントからサービスに送信されるすべてのメッセージにクレジット カード カスタム トークンが追加され、そのコンテンツは自動的に署名および暗号化されます。public static class BindingHelper { public static Binding CreateCreditCardBinding() { HttpTransportBindingElement httpTransport = new HttpTransportBindingElement(); // The message security binding element is configured to require a credit card // token that is encrypted with the service's certificate. SymmetricSecurityBindingElement messageSecurity = new SymmetricSecurityBindingElement(); messageSecurity.EndpointSupportingTokenParameters.SignedEncrypted.Add(new CreditCardTokenParameters()); X509SecurityTokenParameters x509ProtectionParameters = new X509SecurityTokenParameters(); x509ProtectionParameters.InclusionMode = SecurityTokenInclusionMode.Never; messageSecurity.ProtectionTokenParameters = x509ProtectionParameters; return new CustomBinding(messageSecurity, httpTransport); } }Public NotInheritable Class BindingHelper Private Sub New() End Sub Public Shared Function CreateCreditCardBinding() As Binding Dim httpTransport As New HttpTransportBindingElement() ' The message security binding element is configured to require a credit card ' token that is encrypted with the service's certificate. Dim messageSecurity As New SymmetricSecurityBindingElement() messageSecurity.EndpointSupportingTokenParameters.SignedEncrypted.Add(New CreditCardTokenParameters()) Dim x509ProtectionParameters As New X509SecurityTokenParameters() x509ProtectionParameters.InclusionMode = SecurityTokenInclusionMode.Never messageSecurity.ProtectionTokenParameters = x509ProtectionParameters Return New CustomBinding(messageSecurity, httpTransport) End Function End Class
このトピックでは、カスタム トークンを実装して使用するために必要なさまざまなコードを示します。 これらのすべてのコードの組み合わせの完全な例については、「 カスタム トークン」を参照してください。
こちらも参照ください
- SecurityToken
- SecurityTokenParameters
- WSSecurityTokenSerializer
- SecurityTokenProvider
- SecurityTokenAuthenticator
- IAuthorizationPolicy
- SecurityTokenRequirement
- SecurityTokenManager
- ClientCredentials
- ServiceCredentials
- SecurityBindingElement
- 手順: クライアント資格情報とサービス資格情報のカスタム作成
- 方法: カスタム セキュリティ トークン認証システムを作成する
- 方法: カスタム セキュリティ トークン プロバイダーを作成する