Serviço de fachada confiável
O exemplo de TrustedFacade demonstra como circular 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 geralmente fica na rede de perímetro (também conhecida como DMZ, zona desmilitarizada e subrrede em tela) 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 é restrito apenas a uma única finalidade.
Esse exemplo consiste nas seguintes etapas:
Cliente 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 autenticação e validação bem-sucedidas, o serviço 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 token de segurança Username
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 cabeçalho Security
.
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. O 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. E a configuração de associação parece com o seguinte exemplo:
<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 corresponde à senha apresentada. No 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 está no arquivo FacadeService.cs
.
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 associação realiza duas coisas. Ela 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, também transmite a identidade do chamador inicial dentro do token de segurança Username
. 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 abaixo 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 inicial para que a infraestrutura de segurança do WCF possa colocá-la na mensagem encaminhada. O nome de usuário do chamador inicial é fornecido na implementação do serviço de fachada pela definição da propriedade ClientCredentials
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 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 está definida na propriedade ClientCredentials
, 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 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 UserNamePasswordValidator
personalizado é 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 método GetCallerIdentity
é 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 propriedade ServiceSecurityContext.Current.AuthorizationContext.ClaimSets
. 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 token de segurança Username
.
Executando 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 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. Para obter mais informações, consulte o procedimento de instalação no final deste tópico.
O seguinte fornece 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 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 variável
%SERVER_NAME%
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 do 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 preenchimento do repositório de certificados do cliente com o certificado do servidor não será exigida.
certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
Para configurar, compilar, e executar o exemplo
Verifique se você executou o Procedimento de instalação única para os exemplos do Windows Communication Foundation.
Para compilar a edição C# ou do Visual Basic .NET da solução, siga as instruções descritas em Como compilar os exemplos do Windows Communication Foundation.
Para executar o exemplo no mesmo computador
Verifique se o caminho inclui a pasta em que Makecert.exe está localizado.
Execute Setup.bat na pasta de instalação do exemplo. Isso instala todos os certificados necessários para executar o exemplo.
Inicie o BackendService.exe do diretório \BackendService\bin em uma janela separada do console
Inicie o FacadeService.exe do diretório \FacadeService\bin em uma janela separada do console
Inicialize o Client.exe a partir do \client\bin. A atividade do cliente é exibida no aplicativo do console do cliente.
Se o cliente e o serviço não puderem se comunicar, confira Dicas de solução de problemas para exemplos de WCF.
Para fazer uma limpeza após o exemplo
- Execute Cleanup.bat na pasta de amostras depois de concluir a execução da amostra.