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.
Remarque : |
---|
La différence entre ce scénario et Sécurité de message avec un client Windows est qu'il ne négocie pas les informations d'identification du 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 |
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).
Remarque : |
---|
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. Vous pouvez le faire de deux façons : |
Utilisez le compte NetworkService ou LocalSystem pour exécuter votre service. Comme ces comptes ont accès à l'ordinateur SPN établi lorsque l'ordinateur joint le domaine Active Directory, WCF génère automatiquement l'élément SPN correct à 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 principal de service pour ce compte de domaine. Une façon de procéder consiste à faire appel à l'utilitaire Setspn.exe. Une fois que le nom principal de service du compte du service a été créé, configurez WCF pour publier ce nom principal de service 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 le sujet suivant les noms principaux de service, le protocole Kerberos et Active Directory, consultez Supplément technique relatif à Kerberos pour Windows (page pouvant être en anglais). Pour plus d'informations sur le sujet suivant les identités de point de terminaison, consultez Modes d'authentification SecurityBindingElement.
' 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("https://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()
// 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("https://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();
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="https://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 destinés à 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 :
Dim cc As New CalculatorClient("EndpointConfigurationName")
CalculatorClient cc = 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.
Remarque : |
---|
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 principal de 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 Service Model Metadata Tool (Svcutil.exe) pour générer le client, le nom principal du service sera propagé automatiquement au client des métadonnées du service (WSDL), si les métadonnées du service contiennent cette information. Pour plus d'informations sur le sujet suivant comment configurer le service pour inclure son nom principal de service dans les métadonnées du service, consultez plus loin la section « Service » dans cette rubrique. Pour plus d'informations sur les noms principaux de service, le protocole Kerberos et Active Directory, consultez Supplément technique relatif à Kerberos pour Windows (page éventuellement en anglais). Pour plus d'informations sur le sujet suivant les identités de point de terminaison, consultez la rubrique Modes d'authentification SecurityBindingElement. |
' 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
// 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();
}
Configuration
Le code ci-dessous configure le client. Notez que l'élément <ServicePrincipalName> doit être défini pour correspondre au nom principal du service enregistré 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="https://localhost/Calculator"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_ICalculator"
contract="ICalculator"
name="WSHttpBinding_ICalculator">
<identity>
<servicePrincipalName value="service_spn_name" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
Voir aussi
Concepts
Vue d'ensemble de la sécurité
Identité du service et authentification