Partager via


Authentificateur de jeton

Cet exemple montre comment implémenter un authentificateur de jeton personnalisé. Un authentificateur de jeton dans Windows Communication Foundation (WCF) est utilisé pour valider le jeton utilisé avec le message, vérifier qu’il est auto-cohérent et authentifier l’identité associée au jeton.

Les authentificateurs de jetons personnalisés sont utiles dans divers cas, tels que :

  • Lorsque vous souhaitez remplacer le mécanisme d’authentification par défaut associé à un jeton.

  • Lorsque vous créez un jeton personnalisé.

Cet exemple illustre les éléments suivants :

  • Comment un client peut s’authentifier à l’aide d’une paire nom d’utilisateur/mot de passe.

  • Comment le serveur peut valider les informations d’identification du client à l’aide d’un authentificateur de jeton personnalisé.

  • Lien entre le code du service WCF et l’authentificateur de jeton personnalisé.

  • Comment le serveur peut être authentifié à l’aide du certificat X.509 du serveur.

Cet exemple montre également comment l’identité de l’appelant est accessible à partir de WCF après le processus d’authentification de jeton personnalisé.

Le service expose un point de terminaison unique pour communiquer avec le service, défini à l’aide du fichier de configuration App.config. Le point de terminaison se compose d'une adresse, d'une liaison et d'un contrat. La liaison est configurée avec une norme wsHttpBinding, avec le mode de sécurité défini sur message - le mode par défaut du wsHttpBinding. Cet exemple définit la norme wsHttpBinding pour utiliser l’authentification du nom d’utilisateur du client. Le service configure également le certificat de service à l’aide du comportement serviceCredentials. Le securityCredentials comportement vous permet de spécifier un certificat de service. Un certificat de service est utilisé par un client pour authentifier le service et fournir une protection des messages. La configuration suivante fait référence au certificat localhost installé pendant l’exemple d’installation, comme décrit dans les instructions d’installation suivantes.

<system.serviceModel>
    <services>
      <service
          name="Microsoft.ServiceModel.Samples.CalculatorService"
          behaviorConfiguration="CalculatorServiceBehavior">
        <host>
          <baseAddresses>
            <!-- configure base address provided by host -->
            <add baseAddress ="http://localhost:8000/servicemodelsamples/service" />
          </baseAddresses>
        </host>
        <!-- use base address provided by host -->
        <endpoint address=""
                  binding="wsHttpBinding"
                  bindingConfiguration="Binding1"
                  contract="Microsoft.ServiceModel.Samples.ICalculator" />
      </service>
    </services>

    <bindings>
      <wsHttpBinding>
        <binding name="Binding1">
          <security mode="Message">
            <message clientCredentialType="UserName" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>

    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <serviceDebug includeExceptionDetailInFaults="False" />
          <!--
          The serviceCredentials behavior allows one to define a service certificate.
          A service certificate is used by a client to authenticate the service and provide message protection.
          This configuration references the "localhost" certificate installed during the setup instructions.
....        -->
          <serviceCredentials>
            <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>

  </system.serviceModel>

La configuration du point de terminaison client se compose d’un nom de configuration, d’une adresse absolue pour le point de terminaison de service, de la liaison et du contrat. La liaison cliente est configurée avec les paramètres appropriés Mode et clientCredentialType.

<system.serviceModel>
    <client>
      <endpoint name=""
                address="http://localhost:8000/servicemodelsamples/service"
                binding="wsHttpBinding"
                bindingConfiguration="Binding1"
                contract="Microsoft.ServiceModel.Samples.ICalculator">
      </endpoint>
    </client>

    <bindings>
      <wsHttpBinding>
        <binding name="Binding1">
          <security mode="Message">
            <message clientCredentialType="UserName" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
  </system.serviceModel>

L’implémentation du client définit le nom d’utilisateur et le mot de passe à utiliser.

static void Main()
{
     ...
     client.ClientCredentials.UserNamePassword.UserName = username;
     client.ClientCredentials.UserNamePassword.Password = password;
     ...
}

Authentificateur de jeton personnalisé

Pour créer un authentificateur de jeton personnalisé, procédez comme suit :

  1. Écrivez un authentificateur de jeton personnalisé.

    L’exemple implémente un authentificateur de jeton personnalisé qui vérifie que le nom d’utilisateur a un format de messagerie valide. Il dérive UserNameSecurityTokenAuthenticator. La méthode la plus importante de cette classe est ValidateUserNamePasswordCore(String, String). Dans cette méthode, l’authentificateur valide le format du nom d’utilisateur et indique également que le nom d’hôte ne provient pas d’un domaine non autorisé. Si les deux conditions sont remplies, elle retourne une collection en lecture seule d’instances IAuthorizationPolicy qui est ensuite utilisée pour fournir des revendications qui représentent les informations stockées dans le jeton de nom d’utilisateur.

    protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateUserNamePasswordCore(string userName, string password)
    {
        if (!ValidateUserNameFormat(userName))
            throw new SecurityTokenValidationException("Incorrect UserName format");
    
        ClaimSet claimSet = new DefaultClaimSet(ClaimSet.System, new Claim(ClaimTypes.Name, userName, Rights.PossessProperty));
        List<IIdentity> identities = new List<IIdentity>(1);
        identities.Add(new GenericIdentity(userName));
        List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1);
        policies.Add(new UnconditionalPolicy(ClaimSet.System, claimSet, DateTime.MaxValue.ToUniversalTime(), identities));
        return policies.AsReadOnly();
    }
    
  2. Fournissez une stratégie d'autorisation retournée par l'authentificateur de jetons personnalisé.

    Cet exemple fournit sa propre implémentation de IAuthorizationPolicy appelé UnconditionalPolicy qui retourne l'ensemble de revendications et d'identités qui lui ont été passées dans son constructeur.

    class UnconditionalPolicy : IAuthorizationPolicy
    {
        String id = Guid.NewGuid().ToString();
        ClaimSet issuer;
        ClaimSet issuance;
        DateTime expirationTime;
        IList<IIdentity> identities;
    
        public UnconditionalPolicy(ClaimSet issuer, ClaimSet issuance, DateTime expirationTime, IList<IIdentity> identities)
        {
            if (issuer == null)
                throw new ArgumentNullException("issuer");
            if (issuance == null)
                throw new ArgumentNullException("issuance");
    
            this.issuer = issuer;
            this.issuance = issuance;
            this.identities = identities;
            this.expirationTime = expirationTime;
        }
    
        public string Id
        {
            get { return this.id; }
        }
    
        public ClaimSet Issuer
        {
            get { return this.issuer; }
        }
    
        public DateTime ExpirationTime
        {
            get { return this.expirationTime; }
        }
    
        public bool Evaluate(EvaluationContext evaluationContext, ref object state)
        {
            evaluationContext.AddToTarget(this, this.issuance);
    
            if (this.identities != null)
            {
                object value;
                IList<IIdentity> contextIdentities;
                if (!evaluationContext.Properties.TryGetValue("Identities", out value))
                {
                    contextIdentities = new List<IIdentity>(this.identities.Count);
                    evaluationContext.Properties.Add("Identities", contextIdentities);
                }
                else
                {
                    contextIdentities = value as IList<IIdentity>;
                }
                foreach (IIdentity identity in this.identities)
                {
                    contextIdentities.Add(identity);
                }
            }
    
            evaluationContext.RecordExpirationTime(this.expirationTime);
            return true;
        }
    }
    
  3. Écrivez un gestionnaire de jetons de sécurité personnalisé.

    Le SecurityTokenManager est utilisé pour créer un SecurityTokenAuthenticator spécifique aux objets SecurityTokenRequirement qui lui sont transmis dans la méthode CreateSecurityTokenAuthenticator. Le gestionnaire de jetons de sécurité est également utilisé pour créer des fournisseurs de jetons et des sérialiseurs de jetons, mais ceux-ci ne sont pas couverts par cet exemple. Dans cet exemple, le gestionnaire de jetons de sécurité personnalisé hérite de la classe ServiceCredentialsSecurityTokenManager et surcharge la méthode CreateSecurityTokenAuthenticator pour retourner un authentificateur personnalisé de jeton de nom d'utilisateur lorsque les exigences de jeton fournies indiquent que l’authentificateur de nom d’utilisateur est demandé.

    public class MySecurityTokenManager : ServiceCredentialsSecurityTokenManager
    {
        MyUserNameCredential myUserNameCredential;
    
        public MySecurityTokenManager(MyUserNameCredential myUserNameCredential)
            : base(myUserNameCredential)
        {
            this.myUserNameCredential = myUserNameCredential;
        }
    
        public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
        {
            if (tokenRequirement.TokenType ==  SecurityTokenTypes.UserName)
            {
                outOfBandTokenResolver = null;
                return new MyTokenAuthenticator();
            }
            else
            {
                return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
            }
        }
    }
    
  4. Écrivez des informations d’identification de service personnalisées.

    La classe d’informations d’identification du service est utilisée pour représenter les informations d’identification configurées pour le service et crée un gestionnaire de jetons de sécurité utilisé pour obtenir des authentificateurs de jetons, des fournisseurs de jetons et des sérialiseurs de jetons.

    public class MyUserNameCredential : ServiceCredentials
    {
    
        public MyUserNameCredential()
            : base()
        {
        }
    
        protected override ServiceCredentials CloneCore()
        {
            return new MyUserNameCredential();
        }
    
        public override SecurityTokenManager CreateSecurityTokenManager()
        {
            return new MySecurityTokenManager(this);
        }
    
    }
    
  5. Configurez le service pour utiliser les informations d’identification personnalisées du service.

    Pour que le service utilise les informations d’identification du service personnalisé, nous supprimons la classe d’informations d’identification de service par défaut après avoir capturé le certificat de service déjà préconfiguré dans les informations d’identification du service par défaut, et configurez la nouvelle instance d’informations d’identification de service pour utiliser les certificats de service préconfigurés et ajouter cette nouvelle instance d’informations d’identification de service aux comportements de service.

    ServiceCredentials sc = serviceHost.Credentials;
    X509Certificate2 cert = sc.ServiceCertificate.Certificate;
    MyUserNameCredential serviceCredential = new MyUserNameCredential();
    serviceCredential.ServiceCertificate.Certificate = cert;
    serviceHost.Description.Behaviors.Remove((typeof(ServiceCredentials)));
    serviceHost.Description.Behaviors.Add(serviceCredential);
    

Pour afficher les informations de l’appelant, vous pouvez utiliser le PrimaryIdentity code suivant. Current contient des informations sur les réclamations relatives à l’appelant actuel.

static void DisplayIdentityInformation()
{
    Console.WriteLine("\t\tSecurity context identity  :  {0}",
            ServiceSecurityContext.Current.PrimaryIdentity.Name);
     return;
}

Lorsque vous exécutez l’exemple, les demandes et réponses de l’opération s’affichent dans la fenêtre de la console cliente. Appuyez sur Entrée dans la fenêtre du client pour arrêter le client.

Configurer le fichier Batch

Le fichier batch Setup.bat inclus dans cet exemple vous permet de configurer le serveur avec des certificats pertinents pour exécuter une application auto-hébergée qui nécessite une sécurité basée sur les certificats du serveur. Ce fichier de commandes doit être modifié pour fonctionner sur plusieurs ordinateurs ou pour fonctionner dans un cas non hébergé.

Voici une brève vue d’ensemble des différentes sections des fichiers batch afin qu’ils puissent être modifiés pour s’exécuter dans une configuration appropriée.

  • Création du certificat de serveur.

    Les lignes suivantes du fichier batch Setup.bat créent le certificat de serveur à utiliser. La %SERVER_NAME% variable spécifie le nom du serveur. Modifiez cette variable pour spécifier votre propre nom de serveur. La valeur par défaut de ce fichier batch est localhost.

    echo ************
    echo Server cert setup starting
    echo %SERVER_NAME%
    echo ************
    echo making server cert
    echo ************
    makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=%SERVER_NAME% -sky exchange -pe
    
  • Installation du certificat de serveur dans le magasin de certificats approuvé du client.

    Les lignes suivantes du fichier batch Setup.bat copient le certificat de serveur dans le répertoire des contacts de confiance du client. Cette étape est requise, car les certificats générés par Makecert.exe ne sont pas implicitement approuvés par le système client. Si vous disposez déjà d’un certificat rooté dans un certificat racine approuvé client( par exemple, un certificat émis par Microsoft), cette étape de remplissage du magasin de certificats client avec le certificat de serveur n’est pas nécessaire.

    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
    

    Remarque

    Le fichier batch d’installation est conçu pour être exécuté à partir d’une invite de commandes du Kit de développement logiciel (SDK) Windows. Il nécessite que la variable d’environnement MSSDK pointe vers le répertoire où le KIT DE développement logiciel (SDK) est installé. Cette variable d’environnement est automatiquement définie dans une invite de commandes du Kit de développement logiciel (SDK) Windows.

Pour configurer et compiler l’exemple

  1. Assurez-vous d’avoir effectué la Procédure d’installation unique pour les exemples Windows Communication Foundation.

  2. Pour générer la solution, suivez les instructions de Création des exemples Windows Communication Foundation.

Pour exécuter l’exemple sur le même ordinateur

  1. Exécutez Setup.bat à partir de l’exemple de dossier d’installation à l’intérieur d’une invite de commandes Visual Studio ouverte avec des privilèges d’administrateur. Cela installe tous les certificats requis pour l’exécution de l’exemple.

    Remarque

    Le fichier de commandes Setup.bat est conçu pour être exécuté à partir d'une fenêtre de commande Visual Studio. La variable d’environnement PATH définie dans l’invite de commandes Visual Studio pointe vers le répertoire qui contient des exécutables requis par le script Setup.bat.

  2. Lancez service.exe à partir de service\bin.

  3. Lancez client.exe à partir de \client\bin. L’activité du client s’affiche sur l’application console cliente.

  4. Si le client et le service ne sont pas en mesure de communiquer, consultez Conseils de résolution des problèmes pour les exemples WCF.

Pour exécuter l’exemple sur différents ordinateurs

  1. Créez un répertoire sur l’ordinateur de service pour les fichiers binaires de service.

  2. Copiez les fichiers de programme de service dans le répertoire de service sur l’ordinateur de service. Copiez également les fichiers Setup.bat et Cleanup.bat sur l’ordinateur de service.

  3. Le nom de sujet de votre certificat de serveur doit contenir le nom de domaine complet de l'ordinateur. Le fichier App.config de service doit être mis à jour pour refléter ce nouveau nom de certificat. Vous pouvez en créer un en utilisant Setup.bat si vous affectez à la variable %SERVER_NAME% le nom d'hôte complet de l'ordinateur sur lequel le service s'exécutera. Notez que vous devez exécuter le fichier Setup.bat à partir d’une Invite de commandes développeur pour Visual Studio ouverte avec des privilèges d’administrateur.

  4. Copiez le certificat de serveur dans le magasin CurrentUser-TrustedPeople du client. Vous n’avez pas besoin de le faire, sauf lorsque le certificat de serveur est émis par un émetteur approuvé par le client.

  5. Dans le fichier App.config sur l’ordinateur de service, modifiez la valeur de l’adresse de base pour spécifier un nom d’ordinateur complet au lieu de localhost.

  6. Sur l’ordinateur de service, exécutez service.exe depuis une invite de commande.

  7. Copiez les fichiers de programme client à partir du dossier \client\bin\, sous le dossier spécifique à la langue, sur l’ordinateur client.

  8. Dans le fichier Client.exe.config sur l’ordinateur client, modifiez la valeur d’adresse du point de terminaison pour qu’il corresponde à la nouvelle adresse de votre service.

  9. Sur l’ordinateur client, lancez Client.exe à partir d’une invite de commande.

  10. Si le client et le service ne sont pas en mesure de communiquer, consultez Conseils de résolution des problèmes pour les exemples WCF.

Pour nettoyer après le test

  1. Exécutez Cleanup.bat dans le dossier d’exemples une fois que vous avez terminé d’exécuter l’exemple.