Compartilhar via


Serviço de fachada confiável

O exemplo TrustedFacade demonstra como fluir informações de identidade do chamador de um serviço para outro usando a infraestrutura de segurança do WCF (Windows Communication Foundation).

É um padrão de design comum para mostrar a funcionalidade oferecida por um serviço à rede pública usando um serviço de fachada. O serviço de fachada normalmente reside na rede de perímetro (também conhecida como DMZ, Zona Desmilitarizada e sub-rede filtrada) e comunica-se com um serviço de backend que implementa a lógica empresarial e tem acesso a dados internos. O canal de comunicação entre o serviço de fachada e o serviço de back-end passa por um firewall e geralmente é limitado apenas para uma única finalidade.

Este exemplo consiste nos seguintes componentes:

  • Cliente de calculadora

  • Serviço de fachada da calculadora

  • Serviço de back-end da calculadora

O serviço de fachada é responsável por validar a solicitação e autenticar o chamador. Após a autenticação e a validação bem-sucedidas, ela encaminha a solicitação para o serviço de back-end usando o canal de comunicação controlado da rede de perímetro para a rede interna. Como parte da solicitação encaminhada, o serviço intermediário inclui informações sobre a identificação do chamador para que o serviço de back-end possa usar essas informações em seu processamento. A identidade do chamador é transmitida usando um Username token de segurança dentro do cabeçalho da mensagem Security . O exemplo usa a infraestrutura de segurança do WCF para transmitir e extrair essas informações do Security cabeçalho.

Importante

O serviço de back-end confia no serviço de fachada para autenticar o chamador. Por isso, o serviço de back-end não autentica o chamador novamente; ele usa as informações de identidade fornecidas pelo serviço de fachada na solicitação encaminhada. Devido a essa relação de confiança, o serviço de back-end deve autenticar o serviço de fachada para garantir que a mensagem encaminhada venha de uma fonte confiável - nesse caso, o serviço de fachada.

Implementação

Há dois caminhos de comunicação neste exemplo. Primeiro é entre o cliente e o serviço de fachada, o segundo é entre o serviço de fachada e o serviço de back-end.

Caminho de comunicação entre o cliente e o serviço de fachada

O cliente no caminho de comunicação do serviço de fachada usa wsHttpBinding com um tipo de credencial de cliente UserName. Isso significa que o cliente usa nome de usuário e senha para autenticar o serviço de fachada e o serviço de fachada usa o certificado X.509 para autenticar o cliente. A configuração de associação se parece com o exemplo a seguir.

<bindings>
  <wsHttpBinding>
    <binding name="Binding1">
      <security mode="Message">
        <message clientCredentialType="UserName"/>
      </security>
    </binding>
  </wsHttpBinding>
</bindings>

O serviço de fachada autentica o chamador usando a implementação personalizada UserNamePasswordValidator. Para fins de demonstração, a autenticação garante apenas que o nome de usuário do chamador corresponda à senha apresentada. Na situação do mundo real, o usuário provavelmente é autenticado usando o Active Directory ou o provedor de associação de ASP.NET personalizado. A implementação do validador reside no FacadeService.cs arquivo.

public class MyUserNamePasswordValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        // check that username matches password
        if (null == userName || userName != password)
        {
            Console.WriteLine("Invalid username or password");
            throw new SecurityTokenValidationException(
                       "Invalid username or password");
        }
    }
}

O validador personalizado é configurado para ser usado dentro do comportamento serviceCredentials no arquivo de configuração de serviço de fachada. Esse comportamento também é usado para configurar o certificado X.509 do serviço.

<behaviors>
  <serviceBehaviors>
    <behavior name="FacadeServiceBehavior">
      <!--The serviceCredentials behavior allows you to define -->
      <!--a service certificate. -->
      <!--A service certificate is used by the service to  -->
      <!--authenticate itself to its clients and to provide  -->
      <!--message protection. -->
      <!--This configuration references the "localhost"  -->
      <!--certificate installed during the setup instructions. -->
      <serviceCredentials>
        <serviceCertificate
               findValue="localhost"
               storeLocation="LocalMachine"
               storeName="My"
               x509FindType="FindBySubjectName" />
        <userNameAuthentication userNamePasswordValidationMode="Custom"
            customUserNamePasswordValidatorType=
           "Microsoft.ServiceModel.Samples.MyUserNamePasswordValidator,
            FacadeService"/>
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>

Caminho de comunicação entre o Serviço de Fachada e o Serviço de Back-End

O serviço de fachada para o caminho de comunicação do serviço de back-end usa um customBinding que consiste em vários elementos de associação. Essa vinculação realiza duas coisas. Ele autentica o serviço de fachada e o serviço de back-end para garantir que a comunicação seja segura e venha de uma fonte confiável. Além disso, ele também transmite a identidade do chamador inicial dentro do Username token de segurança. Nesse caso, somente o nome de usuário do chamador inicial é transmitido para o serviço de back-end, a senha não está incluída na mensagem. Isso ocorre porque o serviço de back-end confia no serviço de fachada para autenticar o chamador antes de encaminhar a solicitação para ele. Como o serviço de fachada faz a autenticação no serviço de back-end, ele pode confiar nas informações contidas na solicitação encaminhada.

Veja a seguir a configuração de associação para esse caminho de comunicação.

<bindings>
  <customBinding>
    <binding name="ClientBinding">
      <security authenticationMode="UserNameOverTransport"/>
      <windowsStreamSecurity/>
      <tcpTransport/>
    </binding>
  </customBinding>
</bindings>

O elemento de associação de <segurança> cuida da transmissão e extração de nome de usuário do chamador inicial. O <windowsStreamSecurity> e <o tcpTransport> cuidam da autenticação de serviços de fachada e back-end e proteção de mensagens.

Para encaminhar a solicitação, a implementação do serviço de fachada deve fornecer o nome de usuário do chamador original para que a infraestrutura de segurança do WCF possa inseri-lo na mensagem encaminhada. O nome de usuário do chamador inicial é fornecido na implementação do serviço de fachada ao defini-lo na propriedade ClientCredentials da instância de proxy do cliente que o serviço de fachada usa para se comunicar com o serviço de back-end.

O código a seguir mostra como o método GetCallerIdentity é implementado no serviço de fachada. Outros métodos usam o mesmo padrão.

public string GetCallerIdentity()
{
    CalculatorClient client = new CalculatorClient();
    client.ClientCredentials.UserName.UserName = ServiceSecurityContext.Current.PrimaryIdentity.Name;
    string result = client.GetCallerIdentity();
    client.Close();
    return result;
}

Conforme mostrado no código anterior, a senha não é definida na ClientCredentials propriedade, apenas o nome de usuário é definido. A infraestrutura de segurança do WCF cria um token de segurança de nome de usuário sem uma senha nesse caso, que é exatamente o que é necessário nesse cenário.

No serviço de back-end, as informações contidas no token de segurança de nome de usuário devem ser autenticadas. Por padrão, a segurança do WCF tenta mapear o usuário para uma conta do Windows usando a senha fornecida. Nesse caso, não há nenhuma senha fornecida e o serviço de back-end não é necessário para autenticar o nome de usuário porque a autenticação já foi executada pelo serviço de fachada. Para implementar essa funcionalidade no WCF, um personalizado UserNamePasswordValidator é fornecido que só impõe que um nome de usuário seja especificado no token e não execute nenhuma autenticação adicional.

public class MyUserNamePasswordValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        // Ignore the password because it is empty,
        // we trust the facade service to authenticate the client.
        // Accept the username information here so that the
        // application gets access to it.
        if (null == userName)
        {
            Console.WriteLine("Invalid username");
            throw new
             SecurityTokenValidationException("Invalid username");
        }
    }
}

O validador personalizado é configurado para ser usado dentro do comportamento serviceCredentials no arquivo de configuração de serviço de fachada.

<behaviors>
  <serviceBehaviors>
    <behavior name="BackendServiceBehavior">
      <serviceCredentials>
        <userNameAuthentication userNamePasswordValidationMode="Custom"
           customUserNamePasswordValidatorType=
          "Microsoft.ServiceModel.Samples.MyUserNamePasswordValidator,
           BackendService"/>
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>

Para extrair as informações de nome de usuário e informações sobre a conta de serviço de fachada confiável, a implementação do serviço de back-end usa a classe ServiceSecurityContext. O código a seguir mostra como o GetCallerIdentity método é implementado.

public string GetCallerIdentity()
{
    // Facade service is authenticated using Windows authentication.
    //Its identity is accessible.
    // On ServiceSecurityContext.Current.WindowsIdentity.
    string facadeServiceIdentityName =
          ServiceSecurityContext.Current.WindowsIdentity.Name;

    // The client name is transmitted using Username authentication on
    //the message level without the password
    // using a supporting encrypted UserNameToken.
    // Claims extracted from this supporting token are available in
    // ServiceSecurityContext.Current.AuthorizationContext.ClaimSets
    // collection.
    string clientName = null;
    foreach (ClaimSet claimSet in
        ServiceSecurityContext.Current.AuthorizationContext.ClaimSets)
    {
        foreach (Claim claim in claimSet)
        {
            if (claim.ClaimType == ClaimTypes.Name &&
                                   claim.Right == Rights.Identity)
            {
                clientName = (string)claim.Resource;
                break;
            }
        }
    }
    if (clientName == null)
    {
        // In case there was no UserNameToken attached to the request.
        // In the real world implementation the service should reject
        // this request.
        return "Anonymous caller via " + facadeServiceIdentityName;
    }

    return clientName + " via " + facadeServiceIdentityName;
}

As informações da conta de serviço de fachada são extraídas usando a propriedade ServiceSecurityContext.Current.WindowsIdentity. Para acessar as informações sobre o chamador inicial, o serviço de back-end usa a ServiceSecurityContext.Current.AuthorizationContext.ClaimSets propriedade. O serviço procura uma declaração Identity com um tipo Name. Essa declaração é gerada automaticamente pela infraestrutura de segurança do WCF a partir das informações contidas no Username token de segurança.

Executando o exemplo

Quando você executa o exemplo, as solicitações e respostas da operação são exibidas na janela do console do cliente. Pressione ENTER na janela do cliente para desligar o cliente. Você pode pressionar ENTER nas janelas do console de serviço de fachada e back-end para desligar os serviços.

Username authentication required.
Provide a valid machine or domain ac
   Enter username:
user
   Enter password:
****
user via MyMachine\testaccount
Add(100,15.99) = 115.99
Subtract(145,76.54) = 68.46
Multiply(9,81.25) = 731.25
Divide(22,7) = 3.14285714285714

Press <ENTER> to terminate client.

O arquivo em lote Setup.bat incluído no exemplo de cenário de Fachada Confiável permite configurar o servidor com um certificado relevante para executar o serviço de fachada que requer segurança com base no certificado para se autenticar no cliente. Consulte o procedimento de instalação no final deste tópico para obter detalhes.

O seguinte fornece uma breve visão geral das diferentes seções dos arquivos em lotes.

  • Criando o certificado do servidor.

    As linhas a seguir do arquivo em lote Setup.bat criam o certificado do servidor a ser usado.

    echo ************
    echo Server cert setup starting
    echo %SERVER_NAME%
    echo ************
    echo making server cert
    echo ************
    makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=%SERVER_NAME% -sky exchange -pe
    

    A %SERVER_NAME% variável especifica o nome do servidor – o valor padrão é localhost. O certificado é armazenado no repositório LocalMachine.

  • Instalação do certificado do serviço de fachada no repositório de certificados confiáveis do cliente.

    A linha a seguir copia o certificado do servidor de fachada para o repositório de pessoas confiáveis do cliente. Essa etapa é necessária porque os certificados gerados por Makecert.exe não são implicitamente confiáveis pelo sistema cliente. Se você já tiver um certificado com raiz em um certificado raiz confiável do cliente, por exemplo, um certificado emitido pela Microsoft, essa etapa de preencher o repositório de certificados do cliente com o certificado do servidor não será necessária.

    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
    

Para configurar, compilar e executar o exemplo

  1. Verifique se você executou o Procedimento de instalação avulsa dos exemplos do Windows Communication Foundation.

  2. Para compilar a edição .NET do C# ou do Visual Basic da solução, siga as instruções contidas em Como Compilar as Amostras do Windows Communication Foundation.

Para executar o exemplo no mesmo computador

  1. Verifique se o caminho inclui a pasta em que Makecert.exe está localizado.

  2. Execute Setup.bat na pasta de instalação do exemplo. Isso instala todos os certificados necessários para executar o exemplo.

  3. Inicie o BackendService.exe do diretório \BackendService\bin em uma janela de console separada

  4. Inicie o FacadeService.exe do diretório \FacadeService\bin em uma janela de console separada

  5. Inicie Client.exe de \client\bin. A atividade do cliente é exibida no aplicativo de console do cliente.

  6. Se o cliente e o serviço não puderem se comunicar, confira Dicas de solução de problemas para exemplos de WCF.

Para limpar após a amostra

  1. Execute Cleanup.bat na pasta de exemplos depois de concluir a execução do exemplo.