Serviço de fachada confiável

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

É um padrão de design comum expor a funcionalidade fornecida 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 se comunica com um serviço de back-end que implementa a lógica de negócios 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 da calculadora

  • Serviço de fachada com calculadora

  • Serviço de back-end da calculadora

O serviço de fachada é responsável por validar o pedido e autenticar o chamador. Após a autenticação e validação bem-sucedidas, ele 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 de fachada inclui informações sobre a identidade 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 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; Utiliza as informações de identidade fornecidas pelo serviço de fachada no pedido encaminhado. 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 - neste caso, o serviço de fachada.

Implementação

Há dois caminhos de comunicação neste exemplo. O primeiro é entre o cliente e o serviço de fachada, o segundo é entre o serviço de fachada e o serviço de backend.

Caminho de Comunicação entre o Cliente e o Serviço de Fachada

O caminho de comunicação do cliente para o serviço de fachada usa wsHttpBinding com um UserName tipo de credencial de cliente. Isso significa que o cliente usa nome de usuário e senha para autenticar no serviço de fachada e o serviço de fachada usa o certificado X.509 para autenticar no cliente. A configuração de vinculaçã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 apenas garante que o nome de usuário do chamador corresponda à senha apresentada. Na situação do mundo real, o usuário provavelmente é autenticado usando o Ative Directory ou personalizado ASP.NET provedor de associação. 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 serviceCredentials comportamento no arquivo de configuração do 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 ligação. Esta ligaçã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 proveniente 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, apenas o nome de usuário do chamador inicial é transmitido para o serviço de back-end, a senha não é 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 se autentica no serviço de back-end, o serviço de back-end pode confiar nas informações contidas na solicitação encaminhada.

A seguir está a configuração de ligação para esse caminho de comunicação.

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

O <elemento de vinculação de segurança> cuida da transmissão e extração do 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 inicial para que a infraestrutura de segurança do WCF possa colocá-lo na mensagem encaminhada. O nome de usuário do chamador inicial é fornecido na implementação do serviço de fachada, definindo-o ClientCredentials na propriedade na 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 GetCallerIdentity o método é 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;
}

Como 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 neste 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á 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 realizada pelo serviço de fachada. Para implementar essa funcionalidade no WCF, é fornecido um costume UserNamePasswordValidator que impõe apenas que um nome de usuário é especificado no token e não executa 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 serviceCredentials comportamento no arquivo de configuração do 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 ServiceSecurityContext classe. 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 ServiceSecurityContext.Current.WindowsIdentity propriedade. Para acessar as informações sobre o chamador inicial, o serviço de back-end usa a ServiceSecurityContext.Current.AuthorizationContext.ClaimSets propriedade. Procura uma Identity reivindicação 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.

Executar o exemplo

Quando você executa o exemplo, as solicitações de operação e as respostas 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 da fachada e do console de serviço de 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 baseada em certificado para autenticar-se no cliente. Consulte o procedimento de configuração no final deste tópico para obter detalhes.

A seguir apresentamos uma breve visão geral das diferentes seções dos arquivos em lote.

  • Criação do certificado do servidor.

    As linhas a seguir do arquivo em lotes 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 armazenamento LocalMachine.

  • Instalação do certificado do serviço de fachada no armazenamento de certificados confiável do cliente.

    A linha a seguir copia o certificado do serviço de fachada no repositório de pessoas confiáveis do cliente. Esta 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 enraizado em um certificado raiz confiável do cliente, por exemplo, um certificado emitido pela Microsoft, esta etapa de preencher o armazenamento 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. Certifique-se de ter executado o procedimento de instalação única para os exemplos do Windows Communication Foundation.

  2. Para criar a edição C# ou Visual Basic .NET da solução, siga as instruções em Criando os exemplos do Windows Communication Foundation.

Para executar a amostra na mesma máquina

  1. Certifique-se de que o caminho inclui a pasta onde Makecert.exe está localizado.

  2. Execute Setup.bat a partir da pasta de instalação de 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 a partir do diretório \FacadeService\bin em uma janela de console separada

  5. Inicie Client.exe a partir 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, consulte Dicas de solução de problemas para exemplos de WCF.

Para limpar após a amostra

  1. Execute Cleanup.bat na pasta de exemplos assim que terminar de executar o exemplo.