Condividi tramite


Sicurezza dei messaggi con un client Windows senza negoziazione delle credenziali

Lo scenario seguente illustra un client e un servizio Windows Communication Foundation (WCF) protetti dal protocollo Kerberos.

Il servizio e il client sono nello stesso dominio o sono entrambi in domini attendibili.

Nota

La differenza tra questo scenario e Message Security con un client Windows è che questo scenario non negozia le credenziali del servizio con il servizio prima di inviare il messaggio dell'applicazione. Inoltre, poiché ciò richiede il protocollo Kerberos, questo scenario richiede un dominio Windows.

Sicurezza dei messaggi senza negoziazione delle credenziali

Caratteristica Descrizione
Modalità di sicurezza Message
Interoperabilità Sì, WS-Security con client compatibili con il profilo del token Kerberos
Autenticazione (server) Autenticazione reciproca del server e del client
Autenticazione (client) Autenticazione reciproca del server e del client
Integrità
Riservatezza
Trasporto HTTP
Binding WSHttpBinding

Servizio

Il codice e la configurazione seguenti devono essere eseguiti in modo indipendente. Eseguire una delle operazioni seguenti:

  • Creare un servizio autonomo usando il codice senza alcuna configurazione.

  • Creare un servizio usando la configurazione fornita, ma non definire alcun endpoint.

Codice

Il codice seguente crea un endpoint del servizio che usa la sicurezza del messaggio. Il codice disabilita la negoziazione della credenziale del servizio e la definizione di un token del contesto di sicurezza (SCT, Security Context Token).

Nota

Per usare il tipo di credenziale di Windows senza negoziazione, l'account utente del servizio deve avere accesso al nome dell'entità servizio (SPN, Service Principal Name) registrato con il dominio di Active Directory. Questa operazione può essere eseguita in due modi:

  1. Usare l'account NetworkService o LocalSystem per eseguire il servizio. Poiché questi account hanno accesso al nome dell'entità servizio (SPN) del computer che viene definito quando il computer viene associato al dominio di Active Directory, WCF genera automaticamente l'elemento SPN corretto all'interno dell'endpoint del servizio nei metadati (WSDL) del servizio.

  2. Usare un account di dominio Active Directory arbitrario per eseguire il servizio. In questo caso è necessario definire un SPN per questo account di dominio. A tale scopo è possibile usare l'utilità Setspn.exe. Dopo aver creato il nome dell'entità servizio per l'account del servizio, configurare WCF per la pubblicazione del nome dell'entità servizio nei client del servizio tramite i relativi metadati (WSDL). Questa operazione viene eseguita impostando l'identità per l'endpoint esposto o tramite un file di configurazione dell'applicazione o tramite codice. Nell'esempio seguente l'identità viene pubblicata a livello di programmazione.

Per altre informazioni sui nomi SPN, il protocollo Kerberos e Active Directory, vedere Supplemento tecnico Kerberos per Windows. Per altre informazioni sulle identità degli endpoint, vedere Modalità di autenticazione 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()

Impostazione

Invece del codice, è possibile usare la configurazione seguente:

<?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

Il codice e la configurazione seguenti devono essere eseguiti in modo indipendente. Eseguire una delle operazioni seguenti:

  • Creare un client autonomo usando il codice (e il codice client).

  • Creare un client che non definisce alcun indirizzo di endpoint. Usare invece il costruttore client che accetta il nome della configurazione come argomento. Ad esempio:

    CalculatorClient cc = new CalculatorClient("EndpointConfigurationName");
    
    Dim cc As New CalculatorClient("EndpointConfigurationName")
    

Codice

Nel codice seguente viene configurato il client. La modalità di sicurezza è impostata su Messaggio e il tipo di credenziale client è impostato su Windows. Le proprietà NegotiateServiceCredential e EstablishSecurityContext sono impostate su false.

Nota

Per usare un tipo di credenziale di Windows senza negoziazione, il client deve essere configurato con il nome di entità servizio dell'account del servizio prima di iniziare la comunicazione con il servizio. Il client usa il nome dell'entità servizio (SPN) per ottenere il token Kerberos per autenticare e proteggere la comunicazione con il servizio. L'esempio seguente mostra come configurare il client con l'SPN del servizio. Se si usa lo strumento ServiceModel Metadata Utility (Svcutil.exe) per generare il client, il nome SPN del servizio verrà propagato automaticamente al client dai metadati del servizio (WSDL), se i metadati del servizio contengono tali informazioni. Per altre informazioni su come configurare il servizio per includere il nome SPN nei metadati del servizio, vedere la sezione "Servizio" più avanti in questo argomento.

Per ulteriori informazioni sugli SPN, su Kerberos e su Active Directory, vedere la pagina relativa al supplemento tecnico Kerberos per Windows. Per altre informazioni sulle identità degli endpoint, vedere l'argomento Modalità di autenticazione 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

Impostazione

Nel codice seguente viene configurato il client. Notare che l'elemento <servicePrincipalName> deve essere impostato in modo da corrispondere all'SPN del servizio registrato per l'account del servizio nel dominio di 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>

Vedi anche