Meddelandesäkerhet med en Windows-klient utan förhandling med autentiseringsuppgifter
I följande scenario visas en WCF-klient (Windows Communication Foundation) som skyddas av Kerberos-protokollet.
Både tjänsten och klienten finns i samma domän eller betrodda domäner.
Kommentar
Skillnaden mellan det här scenariot och Meddelandesäkerhet med en Windows-klient är att det här scenariot inte förhandlar om tjänstens autentiseringsuppgifter med tjänsten innan programmeddelandet skickas. Eftersom detta kräver Kerberos-protokollet kräver det här scenariot dessutom en Windows-domänmiljö.
Characteristic | beskrivning |
---|---|
Säkerhetsläge | Meddelande |
Samverkan | Ja, WS-Security med Kerberos-tokenprofilkompatibla klienter |
Autentisering (server) | Ömsesidig autentisering av servern och klienten |
Autentisering (klient) | Ömsesidig autentisering av servern och klienten |
Integritet | Ja |
Sekretess | Ja |
Transport | HTTP |
Bindning | WSHttpBinding |
Tjänst
Följande kod och konfiguration är avsedda att köras oberoende av varandra. Gör något av följande:
Skapa en fristående tjänst med hjälp av koden utan konfiguration.
Skapa en tjänst med den angivna konfigurationen, men definiera inga slutpunkter.
Kod
Följande kod skapar en tjänstslutpunkt som använder meddelandesäkerhet. Koden inaktiverar förhandlingar om tjänstautentiseringsuppgifter och inrättandet av en säkerhetskontexttoken (SCT).
Kommentar
Om du vill använda Windows-autentiseringstypen utan förhandling måste tjänstens användarkonto ha åtkomst till tjänstens huvudnamn (SPN) som är registrerat med Active Directory-domänen. Du kan göra detta på två sätt:
NetworkService
LocalSystem
Använd eller-kontot för att köra tjänsten. Eftersom dessa konton har åtkomst till datorns SPN som upprättas när datorn ansluter till Active Directory-domänen genererar WCF automatiskt rätt SPN-element i tjänstens slutpunkt i tjänstens metadata (Web Services Description Language eller WSDL).Använd ett godtyckligt Active Directory-domänkonto för att köra tjänsten. I det här fallet måste du upprätta ett SPN för det domänkontot. Ett sätt att göra detta är att använda verktyget Setspn.exe verktyg. När SPN har skapats för tjänstens konto konfigurerar du WCF för att publicera det SPN till tjänstens klienter via dess metadata (WSDL). Detta görs genom att ange slutpunktsidentiteten för den exponerade slutpunkten, antingen genom en programkonfigurationsfil eller kod. I följande exempel publiceras identiteten programmatiskt.
Mer information om SPN, Kerberos-protokollet och Active Directory finns i Kerberos Tekniska tillägg för Windows. Mer information om slutpunktsidentiteter finns i SecurityBindingElement-autentiseringslägen.
// 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()
Konfiguration
Följande konfiguration kan användas i stället för koden.
<?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>
Klient
Följande kod och konfiguration är avsedda att köras oberoende av varandra. Gör något av följande:
Skapa en fristående klient med hjälp av koden (och klientkoden).
Skapa en klient som inte definierar några slutpunktsadresser. Använd i stället klientkonstruktorn som tar konfigurationsnamnet som argument. Till exempel:
CalculatorClient cc = new CalculatorClient("EndpointConfigurationName");
Dim cc As New CalculatorClient("EndpointConfigurationName")
Kod
Följande kod konfigurerar klienten. Säkerhetsläget är inställt på Meddelande och klientens autentiseringsuppgiftstyp är inställd på Windows. Observera att NegotiateServiceCredential egenskaperna och EstablishSecurityContext är inställda på false
.
Kommentar
Om du vill använda Windows-autentiseringsuppgifter utan förhandling måste klienten konfigureras med tjänstens konto-SPN innan kommunikationen med tjänsten påbörjas. Klienten använder SPN för att hämta Kerberos-token för att autentisera och skydda kommunikationen med tjänsten. Följande exempel visar hur du konfigurerar klienten med tjänstens SPN. Om du använder verktyget ServiceModel-metadataverktyg (Svcutil.exe) för att generera klienten, sprids tjänstens SPN automatiskt till klienten från tjänstens metadata (WSDL), om tjänstens metadata innehåller den informationen. Mer information om hur du konfigurerar tjänsten för att inkludera dess SPN i tjänstens metadata finns i avsnittet "Tjänst" senare i det här avsnittet.
Mer information om SPN, Kerberos och Active Directory finns i Kerberos Tekniska tillägg för Windows. Mer information om slutpunktsidentiteter finns i avsnittet SecurityBindingElement Authentication Modes (Autentiseringslägen för 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
Konfiguration
Följande kod konfigurerar klienten. Observera att elementet <servicePrincipalName> måste anges för att matcha tjänstens SPN som registrerat för tjänstens konto i Active Directory-domänen.
<?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>