Sécurité de message avec un client Windows sans négociation d'informations d'identification
Le scénario suivant montre un client et un service Windows Communication Foundation (WCF) sécurisés par le protocole Kerberos.
Le service et le client appartiennent au même domaine ou domaines approuvés.
Notes
La différence entre ce scénario et le scénario Sécurité des messages avec un client Windows est qu'il n’y a pas de négociation des informations d'identification de service avec le service avant d'envoyer le message d'application. En outre, comme cette opération requiert le protocole Kerberos, ce scénario requiert un environnement de domaine Windows.
Caractéristique | Description |
---|---|
Mode de sécurité | Message |
Interopérabilité | Oui, WS-Security avec des clients compatibles avec le profil de jeton Kerberos |
Authentification (serveur) | Authentification mutuelle du serveur et du client |
Authentification (client) | Authentification mutuelle du serveur et du client |
Intégrité | Oui |
Confidentialité | Oui |
Transport | HTTP |
Liaison | WSHttpBinding |
Service
La configuration et le code ci-dessous sont conçus pour s'exécuter indépendamment. Effectuez l’une des opérations suivantes :
Créez un service autonome à l'aide du code sans configuration.
Créez un service à l'aide de la configuration fournie, mais ne définissez pas de point de terminaison.
Code
Le code ci-dessous crée un point de terminaison de service qui utilise la sécurité de message. Le code désactive la négociation des informations d'identification du service, et l'établissement d'un jeton de contexte de sécurité (SCT).
Notes
Pour utiliser le type d'informations d'identification Windows sans négociation, le compte d'utilisateur du service doit avoir accès au nom de principal du service (SPN) enregistré avec le domaine Active Directory. Il existe deux méthodes pour le faire :
Utilisez le compte
NetworkService
ouLocalSystem
pour exécuter votre service. Comme ces comptes ont accès au SPN de l’ordinateur établi lorsque l’ordinateur rejoint le domaine Active Directory, WCF génère automatiquement l’élément SPN approprié à l’intérieur du point de terminaison du service dans les métadonnées du service (Web Services Description Language ou WSDL).Utilisez un compte de domaine Active Directory arbitraire pour exécuter votre service. Dans ce cas, vous devez établir un nom de principal du service pour ce compte de domaine. Une façon de procéder consiste à faire appel à l'utilitaire Setspn.exe. Une fois que le SPN du compte du service a été créé, configurez WCF pour publier ce SPN sur les clients du service par le biais de ses métadonnées (WSDL). Cette opération s'effectue en définissant l'identité de point de terminaison pour le point de terminaison exposé, par le biais d'un fichier de configuration de l'application ou du code. L'exemple suivant publie l'identité par programme.
Pour plus d’informations sur les SPN, le protocole Kerberos et Active Directory, consultez Supplément technique relatif à Kerberos pour Windows. Pour plus d’informations sur les identités de point de terminaison, consultez Modes d’authentification SecurityBindingElement.
// Create the service host.
ServiceHost myServiceHost = new ServiceHost(typeof(Calculator));
// Create the binding.
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType =
MessageCredentialType.Windows;
// Disable credential negotiation and establishment of the
// security context.
binding.Security.Message.NegotiateServiceCredential = false;
binding.Security.Message.EstablishSecurityContext = false;
// Create a URI for the endpoint address.
Uri httpUri = new Uri("http://localhost/Calculator");
// Create the EndpointAddress with the SPN for the Identity.
EndpointAddress ea = new EndpointAddress(httpUri,
EndpointIdentity.CreateSpnIdentity("service_spn_name"));
// Get the contract from the ICalculator interface (not shown here).
// See the sample applications for an example of the ICalculator.
ContractDescription contract = ContractDescription.GetContract(
typeof(ICalculator));
// Create a new ServiceEndpoint.
ServiceEndpoint se = new ServiceEndpoint(contract, binding, ea);
// Add the service endpoint to the service.
myServiceHost.Description.Endpoints.Add(se);
// Open the service.
myServiceHost.Open();
Console.WriteLine("Listening...");
Console.ReadLine();
// Close the service.
myServiceHost.Close();
' Create the service host.
Dim myServiceHost As New ServiceHost(GetType(ServiceModel.Calculator))
' Create the binding.
Dim binding As New WSHttpBinding()
binding.Security.Mode = SecurityMode.Message
binding.Security.Message.ClientCredentialType = _
MessageCredentialType.Windows
' Disable credential negotiation and establishment of the
' security context.
binding.Security.Message.NegotiateServiceCredential = False
binding.Security.Message.EstablishSecurityContext = False
' Create a URI for the endpoint address.
Dim httpUri As New Uri("http://localhost/Calculator")
' Create the EndpointAddress with the SPN for the Identity.
Dim ea As New EndpointAddress(httpUri, _
EndpointIdentity.CreateSpnIdentity("service_spn_name"))
' Get the contract from the ICalculator interface (not shown here).
' See the sample applications for an example of the ICalculator.
Dim contract As ContractDescription = ContractDescription.GetContract(GetType(ICalculator))
' Create a new ServiceEndpoint.
Dim se As New ServiceEndpoint(contract, binding, ea)
' Add the service endpoint to the service.
myServiceHost.Description.Endpoints.Add(se)
' Open the service.
myServiceHost.Open()
Console.WriteLine("Listening...")
Console.ReadLine()
' Close the service.
myServiceHost.Close()
Configuration
La configuration ci-dessous peut être utilisée à la place du code.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<behaviors />
<services>
<service behaviorConfiguration="" name="ServiceModel.Calculator">
<endpoint address="http://localhost/Calculator"
binding="wsHttpBinding"
bindingConfiguration="KerberosBinding"
name="WSHttpBinding_ICalculator"
contract="ServiceModel.ICalculator"
listenUri="net.tcp://localhost/metadata" >
<identity>
<servicePrincipalName value="service_spn_name" />
</identity>
</endpoint>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="KerberosBinding">
<security>
<message negotiateServiceCredential="false"
establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client />
</system.serviceModel>
</configuration>
Client
La configuration et le code ci-dessous sont conçus pour s'exécuter indépendamment. Effectuez l’une des opérations suivantes :
Créez un client autonome à l'aide du code (et du code client).
Créez un client qui ne définit pas d'adresse de point de terminaison. Au lieu de cela, utilisez le constructeur client qui accepte le nom de configuration comme argument. Par exemple :
CalculatorClient cc = new CalculatorClient("EndpointConfigurationName");
Dim cc As New CalculatorClient("EndpointConfigurationName")
Code
Le code ci-dessous configure le client. Le mode de sécurité a la valeur Message, et le type d'informations d'identification du client a la valeur Windows. Notez que les propriétés NegotiateServiceCredential et EstablishSecurityContext ont la valeur false
.
Notes
Pour utiliser le type d'informations d'identification Windows sans négociation, le client doit être configuré avec le compte SPN du service avant de commencer la communication avec le service. Le client utilise le nom de principal du service pour obtenir le jeton Kerberos afin d'authentifier et de sécuriser la communication avec le service. L'exemple suivant montre comment configurer le client avec le nom principal du service. Si vous utilisez l’outil ServiceModel Metadata Utility Tool (Svcutil.exe) pour générer le client, le SPN du service sera propagé automatiquement vers le client des métadonnées du service (WSDL), si les métadonnées du service contiennent cette information. Pour plus d’informations sur la configuration du service afin d’inclure son SPN dans ses métadonnées, consultez la section « Service » plus loin dans cette rubrique.
Pour plus d’informations sur les SPN, Kerberos et Active Directory, consultez Supplément technique relatif à Kerberos pour Windows. Pour plus d’informations sur les identités de point de terminaison, consultez la rubrique Modes d’authentification SecurityBindingElement.
// Create the binding.
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType =
MessageCredentialType.Windows;
// Disable credential negotiation and the establishment of
// a security context.
myBinding.Security.Message.NegotiateServiceCredential = false;
myBinding.Security.Message.EstablishSecurityContext = false;
// Create the endpoint address and set the SPN identity.
// The SPN must match the identity of the service's SPN.
// If using SvcUtil to generate a configuration file, the SPN
// will be published as the <servicePrincipalName> element under the
// <identity> element.
EndpointAddress ea = new EndpointAddress(
new Uri("http://machineName/Calculator"),
EndpointIdentity.CreateSpnIdentity("service_spn_name"));
// Create the client.
CalculatorClient cc =
new CalculatorClient(myBinding, ea);
// Begin using the client.
try
{
cc.Open();
Console.WriteLine(cc.Add(200, 1111));
Console.ReadLine();
// Close the client.
cc.Close();
}
' Create the binding.
Dim myBinding As New WSHttpBinding()
myBinding.Security.Mode = SecurityMode.Message
myBinding.Security.Message.ClientCredentialType = _
MessageCredentialType.Windows
' Disable credential negotiation and the establishment of
' a security context.
myBinding.Security.Message.NegotiateServiceCredential = False
myBinding.Security.Message.EstablishSecurityContext = False
' Create the endpoint address and set the SPN identity.
' The SPN must match the identity of the service's SPN.
' If using SvcUtil to generate a configuration file, the SPN
' will be published as the <servicePrincipalName> element under the
' <identity> element.
Dim ea As New EndpointAddress(New Uri("http://machineName/calculator"), _
EndpointIdentity.CreateSpnIdentity("service_spn_name"))
' Create the client.
Dim cc As New CalculatorClient(myBinding, ea)
' Begin using the client.
Try
cc.Open()
Console.WriteLine(cc.Add(100, 11))
Console.ReadLine()
' Close the client.
cc.Close()
Catch tex As TimeoutException
Console.WriteLine(tex.Message)
cc.Abort()
Catch cex As CommunicationException
Console.WriteLine(cex.Message)
cc.Abort()
Finally
Console.WriteLine("Closed the client")
Console.ReadLine()
End Try
Configuration
Le code ci-dessous configure le client. Notez que l’élément <servicePrincipalName> doit être défini pour correspondre au SPN du service inscrit pour le compte du service dans le domaine Active Directory.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ICalculator" >
<security mode="Message">
<message clientCredentialType="Windows"
negotiateServiceCredential="false"
establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/Calculator"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_ICalculator"
contract="ICalculator"
name="WSHttpBinding_ICalculator">
<identity>
<servicePrincipalName value="service_spn_name" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>