Partilhar via


Segurança de mensagens com um cliente Windows sem negociação de credenciais

O cenário a seguir mostra um cliente e serviço do Windows Communication Foundation (WCF) protegido pelo protocolo Kerberos.

O serviço e o cliente estão no mesmo domínio ou domínios confiáveis.

Nota

A diferença entre esse cenário e a Segurança de Mensagens com um Cliente Windows é que esse cenário não negocia a credencial de serviço com o serviço antes de enviar a mensagem do aplicativo. Além disso, como isso requer o protocolo Kerberos, esse cenário requer um ambiente de domínio do Windows.

Segurança de mensagens sem negociação de credenciais

Characteristic Description
Modo de Segurança Mensagem
Interoperabilidade Sim, WS-Security com clientes compatíveis com perfil de token Kerberos
Autenticação (Servidor) Autenticação mútua do servidor e do cliente
Autenticação (Cliente) Autenticação mútua do servidor e do cliente
Integridade Sim
Confidencialidade Sim
Transporte HTTP
Enlace WSHttpBinding

Serviço

O código e a configuração a seguir devem ser executados de forma independente. Execute um dos seguintes procedimentos:

  • Crie um serviço autônomo usando o código sem configuração.

  • Crie um serviço usando a configuração fornecida, mas não defina nenhum ponto de extremidade.

Código

O código a seguir cria um ponto de extremidade de serviço que usa segurança de mensagem. O código desabilita a negociação de credenciais de serviço e o estabelecimento de um token de contexto de segurança (SCT).

Nota

Para usar o tipo de credencial do Windows sem negociação, a conta de usuário do serviço deve ter acesso ao SPN (nome da entidade de serviço) registrado no domínio do Ative Directory. Você pode fazer isso de duas maneiras:

  1. Use a NetworkService conta ou LocalSystem para executar seu serviço. Como essas contas têm acesso ao SPN da máquina que é estabelecido quando a máquina ingressa no domínio do Ative Directory, o WCF gera automaticamente o elemento SPN adequado dentro do ponto de extremidade do serviço nos metadados do serviço (Web Services Description Language ou WSDL).

  2. Use uma conta de domínio arbitrária do Ative Directory para executar seu serviço. Nesse caso, você precisa estabelecer um SPN para essa conta de domínio. Uma maneira de fazer isso é usar o Setspn.exe ferramenta utilitária. Depois que o SPN for criado para a conta do serviço, configure o WCF para publicar esse SPN para os clientes do serviço por meio de seus metadados (WSDL). Isso é feito definindo a identidade do ponto de extremidade para o ponto de extremidade exposto, por meio de um arquivo de configuração de aplicativo ou código. O exemplo a seguir publica a identidade programaticamente.

Para obter mais informações sobre SPNs, o protocolo Kerberos e o Ative Directory, consulte Suplemento técnico Kerberos para Windows. Para obter mais informações sobre identidades de ponto de extremidade, consulte Modos de autenticação 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()

Configuração

A configuração a seguir pode ser usada em vez do código.

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

Cliente

O código e a configuração a seguir devem ser executados de forma independente. Execute um dos seguintes procedimentos:

  • Crie um cliente autônomo usando o código (e o código do cliente).

  • Crie um cliente que não defina nenhum endereço de ponto de extremidade. Em vez disso, use o construtor cliente que usa o nome da configuração como um argumento. Por exemplo:

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

Código

O código a seguir configura o cliente. O modo de segurança é definido como Mensagem e o tipo de credencial do cliente é definido como Windows. Observe que as NegotiateServiceCredential propriedades e EstablishSecurityContext estão definidas como false.

Nota

Para usar o tipo de credencial do Windows sem negociação, o cliente deve ser configurado com o SPN da conta do serviço antes de iniciar a comunicação com o serviço. O cliente usa o SPN para obter o token Kerberos para autenticar e proteger a comunicação com o serviço. O exemplo a seguir mostra como configurar o cliente com o SPN do serviço. Se você estiver usando a ServiceModel Metadata Utility Tool (Svcutil.exe) para gerar o cliente, o SPN do serviço será propagado automaticamente para o cliente a partir dos metadados do serviço (WSDL), se os metadados do serviço contiverem essas informações. Para obter mais informações sobre como configurar o serviço para incluir seu SPN nos metadados do serviço, consulte a seção "Serviço" mais adiante neste tópico.

Para obter mais informações sobre SPNs, Kerberos e Ative Directory, consulte Suplemento técnico Kerberos para Windows. Para obter mais informações sobre identidades de ponto de extremidade, consulte o tópico SecurityBindingElement Authentication Modes .

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

Configuração

O código a seguir configura o cliente. Observe que o <elemento servicePrincipalName> deve ser definido para corresponder ao SPN do serviço conforme registrado para a conta do serviço no domínio do Ative 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>

Consulte também