Procédure : créer un jeton personnalisé

Cette rubrique contient des instructions permettant de créer un jeton de sécurité personnalisé à l'aide de la classe SecurityToken et de l'intégrer à un fournisseur et authentificateur de jetons de sécurité personnalisés. Pour obtenir un exemple de code complet, consultez l’exemple Jeton personnalisé.

Un jeton de sécurité est essentiellement un élément XML utilisé par le framework de sécurité Windows Communication Foundation (WCF) pour représenter des revendications à propos d’un expéditeur dans du message SOAP. La sécurité WCF fournit plusieurs jetons pour les modes d’authentification fournis par le système. Les exemples comprennent un jeton de sécurité de certificat X.509 représenté par la classe X509SecurityToken ou un jeton de sécurité de nom d'utilisateur représenté par la classe UserNameSecurityToken.

Il peut arriver qu'un mode d'authentification ou que des informations d'identification ne soient pas prises en charge par les types fournis. Dans un tel cas, il est nécessaire de créer un jeton de sécurité personnalisé permettant de fournir une représentation XML des informations d'identification personnalisées dans les messages SOAP.

Les procédures suivantes montrent comment créer un jeton de sécurité personnalisé et l’intégrer à une infrastructure de sécurité WCF. Cette rubrique contient des instructions permettant de créer un jeton de carte de crédit utilisé pour passer des informations relatives à la carte de crédit du client au serveur.

Pour plus d’informations sur les informations d’identification personnalisées et le gestionnaire de jetons de sécurité, consultez la Procédure pas à pas : Création d’informations d’identification de client et de service personnalisées.

Consultez l'espace de noms System.IdentityModel.Tokens pour obtenir davantage de classes représentant des jetons de sécurité.

Procédures

Une application cliente doit être créée de manière à permettre la spécification d'informations de carte de crédit pour l'infrastructure de sécurité. Une classe d'informations d'identification client personnalisées permet à l'application d'accéder à ces informations. La première étape consiste à créer une classe qui représente les informations de carte de crédit au sein des informations d'identification client personnalisées.

Pour créer une classe qui représente les informations de carte de crédit au sein des informations d'identification client.

  1. Définissez une nouvelle classe qui représente les informations de carte de crédit pour l'application. L'exemple suivant nomme la classe CreditCardInfo.

  2. Ajoutez les propriétés adéquates à cette classe pour permettre à une application de définir les informations requises pour le jeton personnalisé. Dans notre exemple, cette classe dispose de trois propriétés : CardNumber, CardIssuer et ExpirationDate.

    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
    

Vous devez ensuite créer une classe qui représente le jeton de sécurité personnalisé. Cette classe est utilisée par les classes de fournisseur de jetons de sécurité, d’authentificateur et de sérialiseur pour transmettre les informations relatives au jeton de sécurité à vers et à partir de l’infrastructure de sécurité WCF.

Pour créer une classe de jeton de sécurité personnalisé

  1. Définissez une nouvelle classe dérivée de la classe SecurityToken. Cet exemple crée une classe nommée CreditCardToken.

  2. Remplacez la propriété Id. Cette propriété est utilisée pour obtenir l'identificateur local du jeton de sécurité qui permet de renvoyer à la représentation XML de ce dernier à partir des autres éléments figurant dans les messages SOAP. Dans cet exemple, l'identificateur de jeton peut être passé à cette propriété comme paramètre de constructeur ou un nouvel identificateur aléatoire est généré à chaque fois qu'une instance de jeton de sécurité est créée.

  3. Implémentez la propriété SecurityKeys. Cette propriété retourne une collection de clés de sécurité représentée par l'instance de jeton de sécurité. Ces clés peuvent être utilisées par WCF pour signer ou chiffrer les parties des messages SOAP. Dans cet exemple, le jeton de sécurité de carte de crédit ne peut pas contenir n'importe quelle clé de sécurité, c'est pourquoi l'implémentation retourne toujours une collection vide.

  4. Remplacez les propriétés ValidFrom et ValidTo. Ces propriétés sont utilisées par WCF afin de déterminer si l’instance de jeton de sécurité est valide. Dans cet exemple, seule une date d'expiration est définie pour le jeton de carte de crédit, par conséquent la propriété ValidFrom retourne la valeur DateTime, laquelle représente l'heure et la date de création de l'instance.

    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
    

Lorsqu'un nouveau jeton de sécurité est créé, la classe SecurityTokenParameters doit à nouveau être implémentée. L’implémentation est utilisée dans la configuration de l’élément de liaison de sécurité afin de représenter un nouveau type de jeton. La classe des paramètres de jeton de sécurité sert de modèle, lequel permet de mettre en correspondance la véritable instance de jeton de sécurité lorsqu'un message est traité. Ce modèle contient des propriétés supplémentaires qu'une application peut utiliser afin de spécifier les critères que le jeton de sécurité doit respecter pour pouvoir être utilisé ou authentifié. L’exemple suivant n’ajoute pas de propriétés supplémentaires ; par conséquent, seul le type de jeton de sécurité est mis en correspondance lorsque l’infrastructure WCF recherche une instance de jeton de sécurité à utiliser ou à valider.

Pour créer une classe de paramètres de jeton de sécurité personnalisé

  1. Définissez une nouvelle classe dérivée de la classe SecurityTokenParameters.

  2. Implémentez la méthode CloneCore. Copiez tous les champs internes définis dans votre classe, le cas échéant. Cet exemple ne définit aucun champ supplémentaire.

  3. Implémentez la propriété en lecture seule SupportsClientAuthentication. Cette propriété retourne true si le type de jeton de sécurité représenté par cette classe peut être utilisé pour authentifier un client auprès d'un service. Dans cet exemple, le jeton de sécurité de carte de crédit peut être utilisé pour authentifier un client auprès d'un service.

  4. Implémentez la propriété en lecture seule SupportsServerAuthentication. Cette propriété retourne true si le type de jeton de sécurité représenté par cette classe peut être utilisé pour authentifier un service auprès d'un client. Dans cet exemple, le jeton de sécurité de carte de crédit ne peut pas être utilisé pour authentifier un service auprès d'un client.

  5. Implémentez la propriété en lecture seule SupportsClientWindowsIdentity. Cette propriété retourne true si le type de jeton de sécurité représenté par cette classe peut être mappé à un compte Windows. Si c'est le cas, le résultat de l'authentification est représenté par une instance de la classe WindowsIdentity. Dans cet exemple, le jeton ne peut pas être mappé à un compte Windows.

  6. Implémentez la méthode CreateKeyIdentifierClause(SecurityToken, SecurityTokenReferenceStyle). Cette méthode est appelée par le framework de sécurité WCF lorsque ce dernier requiert une référence à une instance de jeton de sécurité représentée par cette classe de paramètres de jeton de sécurité. La véritable instance de jeton de sécurité et le type SecurityTokenReferenceStyle qui spécifie le type de la référence demandée sont tous les deux passés à cette méthode sous forme d’arguments. Dans cet exemple, seules les références internes sont prises en charge par le jeton de sécurité de carte de crédit. La classe SecurityToken dispose d'une fonctionnalité permettant de créer des références internes ; l'implémentation ne nécessite donc pas de code supplémentaire.

  7. Implémentez la méthode InitializeSecurityTokenRequirement(SecurityTokenRequirement). Cette méthode est appelée par WCF pour convertir l’instance de classe de paramètres de jeton de sécurité en instance de la classe SecurityTokenRequirement. Le résultat est utilisé par les fournisseurs de jeton de sécurité pour créer l'instance de jeton de sécurité adéquate.

    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
    

Les jetons de sécurité sont transmis dans les messages SOAP. Cette opération nécessite un mécanisme de traduction entre la représentation de jeton de sécurité en mémoire et la représentation en transmission. WCF utilise un sérialiseur de jeton de sécurité pour accomplir cette tâche. Chaque jeton personnalisé doit être accompagné par un sérialiseur de jeton de sécurité personnalisé pouvant le sérialiser et le désérialiser à partir des messages SOAP.

Notes

Les clés dérivées sont activées par défaut. Si vous créez un jeton de sécurité personnalisé et que vous l’utilisez comme jeton principal, WCF dérive une clé de celui-ci. Ce faisant, il appelle le sérialiseur de jeton de sécurité personnalisé afin d'écrire SecurityKeyIdentifierClause pour le jeton de sécurité personnalisé pendant la sérialisation du DerivedKeyToken sur le câble. À l'extrémité de réception, lors de la désérialisation du jeton du câble, le sérialiseur DerivedKeyToken attend un élément SecurityTokenReference en tant qu'enfant de niveau supérieur au-dessous de lui. Si le sérialiseur de jeton de sécurité personnalisé n'a pas ajouté d'élément SecurityTokenReference pendant la sérialisation de son type de clause, une exception est levée.

Pour créer un sérialiseur de jeton de sécurité personnalisé

  1. Définissez une nouvelle classe dérivée de la classe WSSecurityTokenSerializer.

  2. Remplacez la méthode CanReadTokenCore(XmlReader). Elle utilise un XmlReader pour lire le flux XML. Cette méthode retourne true si l'implémentation du sérialiseur peut désérialiser le jeton de sécurité en fonction de l'élément en cours. Dans cet exemple, cette méthode vérifie si le nom et l'espace de noms de l'élément XML en cours du lecteur XML sont corrects. Dans le cas contraire, elle appelle l'implémentation de classe de base de cette méthode pour gérer l'élément XML.

  3. Remplacez la méthode ReadTokenCore(XmlReader, SecurityTokenResolver) . Cette méthode lit le contenu XML de jeton de sécurité et construit la représentation en mémoire adéquate lui correspondant. Si elle ne reconnaît pas l'élément XML du lecteur XML passé, elle appelle l'implémentation de base pour traiter les types de jeton fournis par le système.

  4. Remplacez la méthode CanWriteTokenCore(SecurityToken) . Cette méthode retourne true si elle peut convertir la représentation en mémoire du jeton (passée sous forme d'argument) en représentation XML. Dans le cas contraire, elle appelle l'implémentation de la classe de base.

  5. Remplacez la méthode WriteTokenCore(XmlWriter, SecurityToken) . Cette méthode convertit la représentation en mémoire du jeton de sécurité en représentation XML. Si elle ne peut pas effectuer la conversion, elle appelle l'implémentation de la classe de base.

    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
    

Les quatre procédures ci-dessus effectuées, intégrez le jeton de sécurité personnalisé au fournisseur, authentificateur et gestionnaire de jetons de sécurité ainsi qu'aux informations d'identification client et service.

Pour intégrer le jeton de sécurité personnalisé à un fournisseur de jetons de sécurité

  1. Le fournisseur de jeton de sécurité crée, modifie (si nécessaire) et retourne une instance du jeton. Pour créer un fournisseur de jetons de sécurité pour le jeton de sécurité personnalisé, créez une classe qui hérite de la classe SecurityTokenProvider. L'exemple suivant remplace la méthode GetTokenCore pour retourner une instance de CreditCardToken. Pour plus d’informations sur les fournisseurs de jetons de sécurité personnalisés, consultez Guide pratique pour créer un fournisseur de jetons de sécurité personnalisé.

    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
    

Pour intégrer le jeton de sécurité personnalisé à un authentificateur de jetons de sécurité

  1. L'authentificateur de jetons de sécurité valide le contenu du jeton de sécurité lorsque ce dernier est extrait du message. Pour créer un authentificateur personnalisé pour le jeton de sécurité personnalisé, créez une classe qui hérite de la classe SecurityTokenAuthenticator. L'exemple suivant substitue la méthode ValidateTokenCore. Pour plus d’informations sur les authentificateurs de jeton de sécurité personnalisés, consultez Guide pratique pour créer un authentificateur de jetons de sécurité personnalisé.

    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
    

Pour intégrer le jeton de sécurité personnalisé à un gestionnaire de jetons de sécurité

  1. Le gestionnaire de jetons de sécurité crée les instances de fournisseur, d'authentificateur et de sérialiseur de jetons de sécurité appropriées. Pour créer un gestionnaire de jetons de sécurité personnalisé, créez une classe qui hérite de la classe ClientCredentialsSecurityTokenManager. Les principales méthodes de la classe utilisent une spécification SecurityTokenRequirement pour créer le fournisseur approprié ainsi que les informations d'identification client ou service requises. Pour plus d’informations sur les gestionnaires de jetons de sécurité personnalisés, consultez la Procédure pas à pas : Création d’informations d’identification de client et de service personnalisées.

    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
    

Pour intégrer le jeton de sécurité personnalisé aux informations d'identification client et service personnalisées

  1. Les informations d'identification client et service doivent être ajoutées afin de générer une API pour l'application. Cette API permet de spécifier les informations du jeton de sécurité personnalisé qui seront utilisées par l'infrastructure de ce dernier créée précédemment afin de générer son contenu et de l'authentifier. Les exemples suivants montrent comment procéder. Pour plus d’informations sur les informations d’identification de client et de service personnalisées, consultez la Procédure pas à pas : Création d’informations d’identification de client et de service personnalisées.

    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
    

La classe de paramètres de jeton de sécurité personnalisé créée précédemment est utilisée pour indiquer au framework de sécurité WCF qu’un jeton de sécurité personnalisé doit être utilisé lors de la communication avec un service. La procédure suivante indique comment effectuer cette opération.

Pour intégrer le jeton de sécurité personnalisé à la liaison

  1. La classe de paramètres de jeton de sécurité personnalisé doit être spécifiée dans l'une des collections de paramètres de jeton exposées sur la classe SecurityBindingElement. Dans l'exemple suivant, la collection retournée par SignedEncrypted est utilisée. Le code ajoute un jeton personnalisé de carte de crédit à tous les messages envoyés depuis le client au service, le contenu de ce jeton étant automatiquement signé et chiffré.

    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
    

Cette rubrique décrit les différents éléments de code nécessaires à l'implémentation et l'utilisation d'un jeton personnalisé. Pour voir un exemple complet de la façon dont tous ces éléments de code s’ajustent les uns aux autres, consultez Jeton personnalisé.

Voir aussi