方法: カスタム トークンを作成する

ここでは、SecurityToken を使用してカスタムのセキュリティ トークンを作成する方法と、作成したトークンを、カスタム セキュリティ トークン プロバイダーおよび認証システムと統合する方法について説明します。 コード例全体については、「カスタム トークン」サンプルを参照してください。

"セキュリティ トークン" とは、基本的に、Windows Communication Foundation (WCF) セキュリティ フレームワークが SOAP メッセージ内の送信者に関するクレームを表すために使用する XML 要素です。 WCF セキュリティにより、システム指定の認証モードで使用するさまざまなトークンが提供されます。 たとえば、X509SecurityToken クラスによって表される X.509 証明書セキュリティ トークンや、UserNameSecurityToken クラスによって表されるユーザー名セキュリティ トークンなどがあります。

認証モードや資格情報は、指定した種類のトークンではサポートされないことがあります。 そのような場合は、SOAP メッセージ内部のカスタム資格情報の XML 表現を提供するカスタム セキュリティ トークンを作成する必要があります。

以下の手順は、カスタム セキュリティ トークンの作成方法と、これを WCF セキュリティ インフラストラクチャに統合する方法を示しています。 ここでは、クライアントのクレジット カードに関する情報をサーバーに渡す際に使用するクレジット カード トークンを作成します。

カスタム資格情報とセキュリティ トークン マネージャーの詳細については、「チュートリアル: カスタム クライアントおよびサービスの資格情報を作成する」を参照してください。

セキュリティ トークンを表すさまざまなクラスについては、「System.IdentityModel.Tokens 名前空間」を参照してください。

手順

クライアント アプリケーションには、セキュリティ インフラストラクチャにクレジット カード情報を指定する方法を設ける必要があります。 この情報は、カスタムのクライアント資格情報クラスによりアプリケーションに提供されます。 最初に、カスタム クライアント資格情報のクレジット カード情報を表すクラスを作成します。

クライアント資格情報内のクレジット カード情報を表すクラスを作成するには

  1. クレジット カード情報を表す新しいクラスをアプリケーションに定義します。 次の例は、CreditCardInfo クラスを示しています。

  2. 適切なプロパティをクラスに追加し、カスタム トークンに必要な情報をアプリケーションで設定できるようにします。 次の例では、CardNumberCardIssuer、および 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 セキュリティ インフラストラクチャとの間で、セキュリティ トークンに関する情報を受け渡しする際に使用します。

カスタム セキュリティ トークン クラスを作成するには

  1. SecurityToken クラスから派生する新しいクラスを定義します。 CreditCardToken という名前のクラスを作成する例を次に示します。

  2. Id プロパティをオーバーライドします。 このプロパティを使用して、SOAP メッセージ内の他の要素からセキュリティ トークンの XML 表現をポイントするためのセキュリティ トークンのローカル識別子を取得します。 次の例では、トークン識別子をコンストラクター パラメーターとしてこのプロパティに渡すことも、セキュリティ トークン インスタンスを作成するたびに新しいランダムな識別子を生成することもできます。

  3. SecurityKeys プロパティを実装します。 このプロパティは、セキュリティ トークン インスタンスが表すセキュリティ キーのコレクションを返します。 WCF では、これらのキーを使用して、SOAP メッセージの一部に署名したり、暗号化したりできます。 次の例では、クレジット カード セキュリティ トークンにはセキュリティ キーを含めることができません。そのため、実装は、常に空のコレクションを返します。

  4. 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 インフラストラクチャが検索するときに、該当するセキュリティ トークンの種類だけが一致項目になります。

カスタム セキュリティ トークン パラメーター クラスを作成するには

  1. SecurityTokenParameters クラスから派生する新しいクラスを定義します。

  2. CloneCore メソッドを実装します。 クラスで内部フィールドが定義されている場合は、それらをすべてコピーします。 次の例では、追加のフィールドを定義しません。

  3. SupportsClientAuthentication の読み取り専用プロパティを実装します。 このクラスで表されているセキュリティ トークンの種類を使用して、サービスに対するクライアントの認証が可能な場合、このプロパティは true を返します。 次の例では、クレジット カード セキュリティ トークンを使用して、サービスに対するクライアントの認証を行うことができます。

  4. SupportsServerAuthentication の読み取り専用プロパティを実装します。 このクラスで表されているセキュリティ トークンの種類を使用して、クライアントに対するサービスの認証が可能な場合、このプロパティは true を返します。 次の例では、クレジット カード セキュリティ トークンを使用して、クライアントに対するサービスの認証を行うことができません。

  5. SupportsClientWindowsIdentity の読み取り専用プロパティを実装します。 このクラスで表されているセキュリティ トークンの種類を Windows アカウントにマップできる場合、このプロパティは true を返します。 その場合、認証結果が WindowsIdentity クラス インスタンスによって表されます。 次の例では、Windows アカウントにトークンをマップすることができません。

  6. CreateKeyIdentifierClause(SecurityToken, SecurityTokenReferenceStyle) メソッドを実装します。 このメソッドは、このセキュリティ トークン パラメーター クラスによって表されるセキュリティ トークン インスタンスへの参照が必要なときに WCF セキュリティ フレームワークによって呼び出されます。 このメソッドには、実際のセキュリティ トークン インスタンスと、要求されている参照の型を指定する SecurityTokenReferenceStyle の両方が引数として渡されます。 次の例では、内部参照だけがクレジット カード セキュリティ トークンでサポートされます。 SecurityToken クラスは、内部参照を作成する機能を備えているため、実装には追加のコードが必要ありません。

  7. InitializeSecurityTokenRequirement(SecurityTokenRequirement) メソッドを実装します。 WCF では、このメソッドを呼び出して、セキュリティ トークン パラメーター クラス インスタンスを SecurityTokenRequirement クラスのインスタンスに変換します。 変換結果は、適切なセキュリティ トークン インスタンスを作成するためにセキュリティ トークン プロバイダーによって使用されます。

    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 メッセージからシリアル化および逆シリアル化できるカスタム セキュリティ トークン シリアライザーを関連付ける必要があります。

Note

派生キーは、既定で有効になっています。 カスタム セキュリティ トークンを作成し、プライマリ トークンとして使用する場合、WCF では、そこからキーが派生します。 キーを派生する一方、カスタム セキュリティ トークン シリアライザーが呼び出され、SecurityKeyIdentifierClause をシリアル化しながら、そのカスタム セキュリティ トークンの DerivedKeyToken をネットワークに送出します。 受信側では、ネットワーク外でのトークンの逆シリアル化時に、DerivedKeyToken シリアライザーは、トークンのすぐ下のトップレベルの子として SecurityTokenReference 要素を必要とします。 カスタム セキュリティ トークン シリアライザーによる句型のシリアル化時に SecurityTokenReference 要素が追加されていなかった場合、例外がスローされます。

カスタム セキュリティ トークン シリアライザーを作成するには

  1. WSSecurityTokenSerializer クラスから派生する新しいクラスを定義します。

  2. CanReadTokenCore(XmlReader) に基づいて XML ストリームを読み取る XmlReader メソッドをオーバーライドします。 シリアライザー実装が現在の要素に基づいてセキュリティ トークンを逆シリアル化できる場合、このメソッドは true を返します。 次の例では、このメソッドが、XML リーダーの現在の XML 要素が正しい要素名と名前空間を持っているかどうかをチェックします。 持っていない場合は、このメソッドの基本クラスの実装を呼び出して、XML 要素を処理します。

  3. ReadTokenCore(XmlReader, SecurityTokenResolver) メソッドをオーバーライドします。 このメソッドは、セキュリティ トークンの XML コンテンツを読み取り、その適切なメモリ内表現を構築します。 渡された XML リーダーの基盤となる XML 要素を認識できない場合は、基本クラスの実装を呼び出して、システム指定のトークンの種類を処理します。

  4. CanWriteTokenCore(SecurityToken) メソッドをオーバーライドします。 引数として渡されるトークンのメモリ内表現を XML 表現に変換できる場合、このメソッドは true を返します。 変換できない場合は、基本クラスの実装を呼び出します。

  5. 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 つの手順を完了したら、カスタム セキュリティ トークンをセキュリティ トークン プロバイダー、セキュリティ トークン認証システム、セキュリティ トークン マネージャー、クライアント資格情報、およびサービス資格情報と統合します。

カスタム セキュリティ トークンをセキュリティ トークン プロバイダーと統合するには

  1. セキュリティ トークン プロバイダーは、必要に応じて、トークンのインスタンスを作成、変更、および返却します。 カスタム セキュリティ トークンのカスタム プロバイダーを作成するには、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
    

カスタム セキュリティ トークンをセキュリティ トークン認証システムと統合するには

  1. セキュリティ トークン認証システムは、セキュリティ トークンがメッセージから抽出されたときにトークンの内容を検証します。 カスタム セキュリティ トークンのカスタム認証システムを作成するには、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 Class
    
    public 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
    

カスタム セキュリティ トークンをセキュリティ トークン マネージャーと統合するには

  1. セキュリティ トークン マネージャーは、トークン プロバイダー、セキュリティ認証システム、およびトークン シリアライザーの適切なインスタンスを作成します。 カスタム トークン マネージャーを作成するには、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 Class
    
    public 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
    

カスタム セキュリティ トークンをカスタムのクライアント資格情報およびサービス資格情報と統合するには

  1. アプリケーションに 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 Class
    
    public 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 セキュリティ フレームワークに伝えます。 この方法を次の手順に示します。

カスタム セキュリティ トークンをバインディングと統合するには

  1. SecurityBindingElement クラスで公開されるトークン パラメーター コレクションの 1 つで、カスタム セキュリティ トークン パラメーター クラスを指定する必要があります。 次の例では、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
    

このトピックでは、カスタム トークンを実装および使用するために必要なさまざまなコードを示します。 これらのコードをすべて組み合わせた完全な例については、「カスタム トークン」を参照してください。

関連項目