Délégation et emprunt d'identité avec WCF

L'emprunt d'identité est une technique courante utilisée par les services pour restreindre l'accès du client aux ressources d'un domaine de service. Les ressources de domaine de service peuvent être des ressources d'ordinateur, telles que des fichiers locaux (emprunt d'identité), ou une ressource sur un autre ordinateur, tel qu'un partage de fichiers (délégation). Pour obtenir un exemple d'application, consultez Impersonating the Client. Pour obtenir un exemple sur l’utilisation de l’emprunt d’identité, consultez How to: Impersonate a Client on a Service.

Important

Sachez que lors de l'emprunt d'identité d'un client sur un service, le service s'exécute avec les informations d'identification du client, qui peut avoir des privilèges plus élevés que le processus serveur.

Vue d’ensemble

Généralement, les clients appellent un client pour que celui-ci effectue une action au nom du client. L'emprunt d'identité permet au service d'agir comme le client lors de l'exécution de l'action. La délégation permet à un service frontal de transmettre la demande du client à un service principal d'une manière qui permet au service principal d'emprunter l'identité du client. L'emprunt d'identité est une méthode couramment utilisée pour vérifier si un client est autorisé à effectuer une action donnée. La délégation est une méthode permettant de transmettre les fonctions d'emprunt d'identité avec l'identité du client à un service principal. La délégation est une fonctionnalité du domaine Windows qui peut être utilisée dans le cadre de l'authentification Kerberos. La délégation n'est pas la même chose que le flux d'identité et comme la délégation transfère la possibilité d'emprunter l'identité du client sans connaître son mot de passe, elle représente une opération d'un niveau de privilège supérieur au flux d'identité.

L'emprunt d'identité et la délégation nécessitent que le client possède une identité Windows. Si ce n'est pas le cas, la seule option consiste à transmettre l'identité du client au second service.

Principes de base de l'emprunt d'identité

Windows Communication Foundation (WCF) prend en charge l’emprunt d’identité pour diverses informations d’identification du client. Cette rubrique décrit la prise en charge de modèle de service permettant d'emprunter l'identité de l'appelant pendant l'implémentation d'une méthode de service. Elle présente également des scénarios de déploiement courants impliquant l’emprunt d’identité et la sécurité SOAP, ainsi que les options WCF utilisées dans ces scénarios.

Cette rubrique se concentre sur l’emprunt d’identité et la délégation dans WCF lors de l’utilisation de la sécurité SOAP. Vous pouvez également utiliser l’emprunt d’identité et la délégation avec WCF lors de l’utilisation de la sécurité de transport, tel que décrit dans Utilisation de l’emprunt d’identité avec la sécurité de transport.

Deux méthodes

La sécurité SOAP WCF a deux méthodes distinctes pour l’exécution de l’emprunt d’identité. La méthode utilisée dépend de la liaison. L'une concerne l'emprunt d'identité à partir d'un jeton Windows fourni par l'authentification SSPI (Security Support Provider Interface) ou Kerberos, qui est ensuite mis en cache sur le service. La deuxième concerne l'emprunt d'identité à partir d'un jeton Windows fourni par les extensions Kerberos, collectivement appelées S4U (Service-for-User).

Emprunt d'identité avec jeton mis en cache

Vous pouvez effectuer l'emprunt d'identité avec jeton mis en cache à l'aide des éléments suivants :

Emprunt d'identité basé sur S4U

Vous pouvez effectuer l'emprunt d'identité basé sur S4U à l'aide des éléments suivants :

  • WSHttpBinding, WSDualHttpBindinget NetTcpBinding avec une information d'identification de client de certificat que le service peut mapper à un compte Windows valide.

  • Tout CustomBinding qui utilise une information d'identification de client Windows avec la propriété requireCancellation définie à false.

  • Tout CustomBinding qui utilise un nom d'utilisateur ou une information d'identification de client Windows et une conversation sécurisée avec la propriété requireCancellation définie à false.

L'étendue à laquelle le service peut emprunter l'identité du client dépend des privilèges dont le compte de service dispose lorsqu'il tente l'emprunt d'identité, du type d'emprunt d'identité utilisé, et éventuellement de l'étendue d'emprunt d'identité autorisée par le client.

Notes

Lorsque le client et le service s'exécutent sur le même ordinateur et que le client s'exécute sous un compte système (par exemple, Local System ou Network Service), il n'est pas possible d'emprunter l'identité du client lorsqu'une session sécurisée est établie avec les jetons de contexte de sécurité avec état. Une application Windows Forms ou console s'exécute en général sous le compte actuellement connecté, afin que l'emprunt d'identité du compte puisse être effectué par défaut. Toutefois, lorsque le client est une page ASP.NET et que celle-ci est hébergée dans IIS 6.0 ou IIS 7.0, le client s’exécute par défaut sous le compte Network Service. Toutes les liaisons fournies par le système qui prennent en charge des sessions sécurisées utilisent par défaut un jeton de contexte de sécurité sans état. Toutefois, si le client est une page ASP.NET, et que des sessions sécurisées avec jetons de contexte de sécurité (SCT) avec état sont utilisées, l’emprunt de l’identité du client est impossible. Pour plus d’informations sur l’utilisation de jetons de contexte de sécurité (SCT) avec état dans une session sécurisée, consultez Guide pratique pour créer un jeton de contexte de sécurité pour une session sécurisée.

Emprunt d'identité dans une méthode de service : modèle déclaratif

La plupart des scénarios d'emprunt d'identité impliquent l'exécution de la méthode de service dans le contexte de l'appelant. WCF fournit une fonctionnalité d’emprunt d’identité qui facilite cette procédure en permettant à l’utilisateur d’indiquer la spécification d’emprunt d’identité dans l’attribut OperationBehaviorAttribute. Par exemple, dans le code suivant, l’infrastructure WCF emprunte l’identité de l’appelant avant d’exécuter la méthode Hello. Toute tentative d'accès aux ressources natives à l'intérieur de la méthode Hello réussit uniquement si la liste de contrôle d'accès (ACL, Access Control List) de la ressource autorise les privilèges d'accès de l'appelant. Pour activer l'emprunt d'identité, affectez l'une des valeurs d'énumération Impersonation ( ImpersonationOption ou ImpersonationOption.Required ) à la propriété ImpersonationOption.Allowed, tel qu'indiqué dans l'exemple suivant.

Notes

Lorsqu'un service a des informations d'identification plus élevées que le client distant, celles-ci sont utilisées si la propriété Impersonation a la valeur Allowed. En d'autres termes, si un utilisateur à privilèges faibles fournit ses informations d'identification, un service à privilèges plus élevés exécute la méthode avec les informations d'identification du service, et peut utiliser des ressources que l'utilisateur à privilèges faibles n'aurait pas pu utiliser sinon.

[ServiceContract]
public interface IHelloContract
{
    [OperationContract]
    string Hello(string message);
}

public class HelloService : IHelloService
{
    [OperationBehavior(Impersonation = ImpersonationOption.Required)]
    public string Hello(string message)
    {
        return "hello";
    }
}

<ServiceContract()> _
Public Interface IHelloContract
    <OperationContract()> _
    Function Hello(ByVal message As String) As String
End Interface


Public Class HelloService
    Implements IHelloService

    <OperationBehavior(Impersonation:=ImpersonationOption.Required)> _
    Public Function Hello(ByVal message As String) As String Implements IHelloService.Hello
        Return "hello"
    End Function
End Class

L’infrastructure WCF peut emprunter l’identité de l’appelant uniquement si celui-ci est authentifié avec des informations d’identification qui peuvent être mappées à un compte d’utilisateur Windows. Si le service est configuré pour authentifier l'utilisation d'une information d'identification qui ne peut pas être mappée à un compte Windows, la méthode de service n'est pas exécutée.

Notes

Sur Windows XP, l’emprunt d’identité échoue si un jeton de contexte de sécurité (SCT) avec état est créé, ce qui génère un InvalidOperationException. Pour plus d’informations, consultez Scénarios non pris en charge.

Emprunt d'identité dans une méthode de service : modèle impératif

Un appelant n'a parfois pas besoin d'emprunter l'identité de l'ensemble de la méthode de service pour fonctionner, mais uniquement une partie de celle-ci. Dans ce cas, obtenez l'identité Windows de l'appelant à l'intérieur de la méthode de service et exécutez l'emprunt d'identité de manière impérative. Pour ce faire, utilisez la propriété WindowsIdentity de ServiceSecurityContext pour retourner une instance de la classe WindowsIdentity , et appelez la méthode Impersonate avant d'utiliser l'instance.

Notes

Assurez-vous d’utiliser l’instruction Using en Visual Basic ou l’instruction using en C# pour rétablir automatiquement l’action d’emprunt d’identité. Si vous n’utilisez pas l’instruction, ou si vous utilisez un langage de programmation autre que Visual Basic ou C#, assurez-vous de rétablir le niveau d’emprunt d’identité. Si vous ne le faites pas, vous risquez de vous exposer à des attaques par déni de service et d'élévation de privilège.

public class HelloService : IHelloService
{
    [OperationBehavior]
    public string Hello(string message)
    {
        WindowsIdentity callerWindowsIdentity =
        ServiceSecurityContext.Current.WindowsIdentity;
        if (callerWindowsIdentity == null)
        {
            throw new InvalidOperationException
           ("The caller cannot be mapped to a WindowsIdentity");
        }
        using (callerWindowsIdentity.Impersonate())
        {
            // Access a file as the caller.
        }
        return "Hello";
    }
}
Public Class HelloService
    Implements IHelloService

    <OperationBehavior()> _
    Public Function Hello(ByVal message As String) As String _
       Implements IHelloService.Hello
        Dim callerWindowsIdentity As WindowsIdentity = _
            ServiceSecurityContext.Current.WindowsIdentity
        If (callerWindowsIdentity Is Nothing) Then
            Throw New InvalidOperationException( _
              "The caller cannot be mapped to a WindowsIdentity")
        End If
        Dim cxt As WindowsImpersonationContext = callerWindowsIdentity.Impersonate()
        Using (cxt)
            ' Access a file as the caller.
        End Using

        Return "Hello"

    End Function
End Class

Emprunt d'identité pour toutes les méthodes de service

Dans certains cas, vous devez exécuter toutes les méthodes d'un service dans le contexte de l'appelant. Au lieu d'activer explicitement cette fonction par méthode, utilisez ServiceAuthorizationBehavior. Comme indiqué dans le code suivant, affectez ImpersonateCallerForAllOperations à la propriété true. ServiceAuthorizationBehavior est récupéré des collections de comportements de la classe ServiceHost . Notez également que la propriété Impersonation de OperationBehaviorAttribute appliquée à chaque méthode doit également avoir la valeur Allowed ou Required.

// Code to create a ServiceHost not shown.
ServiceAuthorizationBehavior MyServiceAuthorizationBehavior =
    serviceHost.Description.Behaviors.Find<ServiceAuthorizationBehavior>();
MyServiceAuthorizationBehavior.ImpersonateCallerForAllOperations = true;
' Code to create a ServiceHost not shown.
Dim MyServiceAuthorizationBehavior As ServiceAuthorizationBehavior
MyServiceAuthorizationBehavior = serviceHost.Description.Behaviors.Find _
(Of ServiceAuthorizationBehavior)()
MyServiceAuthorizationBehavior.ImpersonateCallerForAllOperations = True

Le tableau suivant décrit le comportement WCF de toutes les combinaisons possibles de ImpersonateCallerForAllServiceOperations et de ImpersonationOption.

ImpersonationOption ImpersonateCallerForAllServiceOperations Comportement
Obligatoire Non applicable WCF emprunte l’identité de l’appelant
Autorisé false WCF n’emprunte pas l’identité de l’appelant
Autorisé true WCF emprunte l’identité de l’appelant
Non autorisé false WCF n’emprunte pas l’identité de l’appelant
Non autorisé true Non autorisé. (Une exception InvalidOperationException est levée.)

Niveau d'emprunt d'identité obtenu à partir des informations d'identification Windows et emprunt d'identité avec jeton mis en cache

Dans certains scénarios, le client contrôle en partie le niveau d'emprunt d'identité que le service effectue lorsqu'une information d'identification de client Windows est utilisée. L'un de ces scénarios se produit lorsque le client spécifie un niveau d'emprunt d'identité à Anonymous. L'autre se produit lors de l'exécution de l'emprunt d'identité avec un jeton mis en cache. Pour ce faire, définissez la propriété AllowedImpersonationLevel de la classe WindowsClientCredential , qui est accessible en tant que propriété de la classe ChannelFactory<TChannel> générique.

Notes

Si vous spécifiez un niveau d'emprunt d'identité à Anonymous, le client ouvre une session sur le service de façon anonyme. Le service doit donc autoriser des ouvertures de session anonymes, indépendamment de l'exécution de l'emprunt d'identité.

Le client peut spécifier le niveau d'emprunt d'identité à Anonymous, Identification, Impersonationou Delegation. Un jeton est uniquement généré au niveau spécifié, tel qu'indiqué dans le code suivant.

ChannelFactory<IEcho> cf = new ChannelFactory<IEcho>("EchoEndpoint");
cf.Credentials.Windows.AllowedImpersonationLevel  =
    System.Security.Principal.TokenImpersonationLevel.Impersonation;
Dim cf As ChannelFactory(Of IEcho) = New ChannelFactory(Of IEcho)("EchoEndpoint")
cf.Credentials.Windows.AllowedImpersonationLevel = _
System.Security.Principal.TokenImpersonationLevel.Impersonation

Le tableau suivant spécifie le niveau d'emprunt d'identité que le service obtient lors de l'emprunt d'identité à partir d'un jeton mis en cache.

Valeur AllowedImpersonationLevel Le Service a SeImpersonatePrivilege Le Service et le client sont capables de délégation Jeton ImpersonationLevelmis en cache
Anonyme Oui n/a Emprunt d'identité
Anonyme Non n/a Identification
Identification n/a n/a Identification
Emprunt d'identité Oui n/a Emprunt d'identité
Emprunt d'identité Non n/a Identification
La délégation Oui Oui La délégation
La délégation Oui Non Emprunt d'identité
La délégation Non n/a Identification

Niveau d'emprunt d'identité obtenu à partir des informations d'identification de nom d'utilisateur et emprunt d'identité avec jeton mis en cache

En passant son nom d’utilisateur et son mot de passe au service, un client permet à WCF de se connecter en tant que cet utilisateur, ce qui revient à affecter Delegation à la propriété AllowedImpersonationLevel. (AllowedImpersonationLevel est disponible sur les classes WindowsClientCredential et HttpDigestClientCredential.) Le tableau suivant indique le niveau d’emprunt d’identité obtenu lorsque le service reçoit des informations d’identification de nom d’utilisateur.

AllowedImpersonationLevel Le Service a SeImpersonatePrivilege Le Service et le client sont capables de délégation Jeton ImpersonationLevelmis en cache
n/a Oui Oui La délégation
n/a Oui Non Emprunt d'identité
n/a Non n/a Identification

Niveau d'emprunt d'identité obtenu à partir de l'emprunt d'identité basé sur S4U

Le Service a SeTcbPrivilege Le Service a SeImpersonatePrivilege Le Service et le client sont capables de délégation Jeton ImpersonationLevelmis en cache
Oui Oui n/a Emprunt d'identité
Oui Non n/a Identification
Non N/A n/a Identification

Mappage d'un certificat client à un compte Windows

Il est possible pour un client de s'authentifier auprès d'un service à l'aide d'un certificat et que le service mappe le client à un compte existant par le biais d'Active Directory. Le code XML suivant indique comment configurer le service pour mapper le certificat.

<behaviors>  
  <serviceBehaviors>  
    <behavior name="MapToWindowsAccount">  
      <serviceCredentials>  
        <clientCertificate>  
          <authentication mapClientCertificateToWindowsAccount="true" />  
        </clientCertificate>  
      </serviceCredentials>  
    </behavior>  
  </serviceBehaviors>  
</behaviors>  

Le code suivant indique comment configurer le service.

// Create a binding that sets a certificate as the client credential type.  
WSHttpBinding b = new WSHttpBinding();  
b.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;  
  
// Create a service host that maps the certificate to a Windows account.  
Uri httpUri = new Uri("http://localhost/Calculator");  
ServiceHost sh = new ServiceHost(typeof(HelloService), httpUri);  
sh.Credentials.ClientCertificate.Authentication.MapClientCertificateToWindowsAccount = true;  

La délégation

Pour déléguer à un service principal, un service doit effectuer une authentification Kerberos multi-leg (SSPI sans NTLM) ou une authentification directe Kerberos au service principal à l'aide de l'identité Windows du client. Pour déléguer à un service principal, créez un ChannelFactory<TChannel> et un canal, puis communiquez par le biais du canal lors de l'emprunt d'identité du client. Avec cette forme de délégation, la distance entre l'emplacement du service principal et le service frontal dépend du niveau d'emprunt d'identité atteint par le service frontal. Lorsque le niveau d'emprunt d'identité est Impersonation, les services frontaux et principaux doivent s'exécuter sur le même ordinateur. Lorsque le niveau d'emprunt d'identité est Delegation, les services frontaux et principaux peuvent être présents sur des ordinateurs séparés ou sur le même ordinateur. L'activation de l'emprunt d'identité au niveau délégation nécessite que la stratégie du domaine Windows soit configurée pour permettre la délégation. Pour plus d’informations sur la configuration d’Active Directory pour la prise en charge de la délégation, consultez Enabling Delegated Authentication(Activation de l’authentification déléguée).

Notes

Lorsqu'un client s'authentifie auprès du service frontal à l'aide d'un nom d'utilisateur et d'un mot de passe qui correspondent à un compte Windows, le service frontal peut s'authentifier auprès du service principal en réutilisant le nom et le mot de passe du client. Il s'agit d'une forme très puissante de flux d'identité, car la transmission d'un nom d'utilisateur et d'un mot de passe au service principal permet à ce service d'effectuer l'emprunt d'identité, mais elle ne constitue pas une délégation en l'absence de l'utilisation de Kerberos. Les contrôles Active Directory sur la délégation ne s'appliquent pas à l'authentification par nom d'utilisateur et par mot de passe.

La délégation comme fonction du niveau d'emprunt d'identité

Niveau d'emprunt d'identité Le service peut effectuer une délégation interprocessus Le service peut effectuer une délégation sur plusieurs ordinateurs
Identification Non Non
Impersonation Oui No
Delegation Oui Oui

L'exemple de code suivant montre comment utiliser la délégation.

public class HelloService : IHelloService
{
    [OperationBehavior(Impersonation = ImpersonationOption.Required)]
    public string Hello(string message)
    {
        WindowsIdentity callerWindowsIdentity = ServiceSecurityContext.Current.WindowsIdentity;
        if (callerWindowsIdentity == null)
        {
            throw new InvalidOperationException
             ("The caller cannot be mapped to a Windows identity.");
        }
        using (callerWindowsIdentity.Impersonate())
        {
            EndpointAddress backendServiceAddress = new EndpointAddress("http://localhost:8000/ChannelApp");
            // Any binding that performs Windows authentication of the client can be used.
            ChannelFactory<IHelloService> channelFactory = new ChannelFactory<IHelloService>(new NetTcpBinding(), backendServiceAddress);
            IHelloService channel = channelFactory.CreateChannel();
            return channel.Hello(message);
        }
    }
}
Public Class HelloService
    Implements IHelloService

    <OperationBehavior(Impersonation:=ImpersonationOption.Required)> _
    Public Function Hello(ByVal message As String) As String Implements IHelloService.Hello
        Dim callerWindowsIdentity As WindowsIdentity = ServiceSecurityContext.Current.WindowsIdentity
        If (callerWindowsIdentity Is Nothing) Then
            Throw New InvalidOperationException("The caller cannot be mapped to a Windows identity.")
        End If

        Dim backendServiceAddress As EndpointAddress = New EndpointAddress("http://localhost:8000/ChannelApp")
        ' Any binding that performs Windows authentication of the client can be used.
        Dim channelFactory As ChannelFactory(Of IHelloService) = _
          New ChannelFactory(Of IHelloService)(New NetTcpBinding(), backendServiceAddress)
        Dim channel As IHelloService = channelFactory.CreateChannel()
        Return channel.Hello(message)
    End Function
End Class

Comment configurer une Application pour utiliser la délégation contrainte

Avant de pouvoir utiliser la délégation contrainte, l'expéditeur, le destinataire et le contrôleur de domaine doivent être configurés en conséquence. La procédure suivante répertorie les étapes qui permettent d'activer la délégation contrainte. Pour des informations sur les différences entre la délégation et la délégation contrainte, consultez la section Windows Server 2003 Kerberos Extensions (Kerberos dans Windows Server 2003) qui traite de la délégation contrainte.

  1. Dans le contrôleur de domaine, désactivez la case à cocher Le compte est sensible et ne peut pas être délégué pour le compte sous lequel s'exécute l'application cliente.

  2. Dans le contrôleur de domaine, activez la case à cocher Le compte est approuvé pour la délégation pour le compte sous lequel s'exécute l'application cliente.

  3. Dans le contrôleur de domaine, configurez l'ordinateur intermédiaire pour qu'il soit approuvé pour la délégation en cliquant sur l'option Approuver l'ordinateur pour la délégation .

  4. Dans le contrôleur de domaine, configurez l'ordinateur intermédiaire pour utiliser la délégation contrainte en cliquant sur l'option N'approuver cet ordinateur que pour la délégation aux services spécifiés .

Pour obtenir des instructions plus détaillées sur la configuration de la délégation contrainte, consultez Transition du protocole Kerberos et délégation contrainte.

Voir aussi