Delegação e representação com o WCF
A representação é uma técnica comum usada por serviços para restringir o acesso do cliente aos recursos de um domínio de serviço. Os recursos de domínio de serviço podem ser recursos de computador, como arquivos locais (representação) ou um recurso em outro computador, como um compartilhamento de arquivos (delegação). Para ver um aplicativo de exemplo, confira Representação do cliente. Para obter um exemplo de como usar a representação, confira Como representar um cliente em um serviço.
Importante
Lembre-se de que, ao representar um cliente em um serviço, o serviço é executado com as credenciais do cliente, que podem ter privilégios mais altos do que o processo do servidor.
Visão geral
Normalmente, os clientes chamam um serviço para que o serviço execute alguma ação em nome do cliente. A representação permite que o serviço atue como o cliente durante a execução da ação. A delegação permite que um serviço front-end encaminhe a solicitação do cliente para um serviço de back-end de forma que o serviço de back-end também possa representar o cliente. A representação costuma ser usada como uma forma de verificar se um cliente está autorizado a executar uma determinada ação, enquanto a delegação é uma maneira de fluir recursos de representação, juntamente com a identidade do cliente, para um serviço de back-end. Delegação é um recurso de domínio do Windows que pode ser usado quando a autenticação baseada em Kerberos é executada. A delegação é diferente do fluxo de identidade e, como transfere a capacidade de representar o cliente sem a posse da senha do cliente, é uma operação com muito mais privilégios do que o fluxo de identidade.
Tanto a representação quanto a delegação exigem que o cliente tenha uma identidade do Windows. Se um cliente não possuir uma identidade do Windows, a única opção disponível será fluir a identidade do cliente para o segundo serviço.
Noções básicas de representação
O WCF (Windows Communication Foundation) dá suporte à representação para diversas credenciais de cliente. Este tópico descreve o suporte ao modelo de serviço para representar o chamador durante a implementação de um método de serviço. Também discute cenários comuns de implantação envolvendo representação e segurança SOAP e opções de WCF nesses cenários.
Este tópico se concentra na representação e na delegação no WCF ao usar a segurança SOAP. Você também pode usar representação e delegação com o WCF ao usar a segurança de transporte, conforme descrito em Usar representação com segurança de transporte.
Dois métodos
A segurança do WCF SOAP tem dois métodos distintos para executar a representação. O método usado depende da associação. Um deles é a representação de um token do Windows obtido da SSPI (Interface do Provedor de Suporte de Segurança) ou da autenticação Kerberos, que é armazenada em cache no serviço. A segunda é a representação de um token do Windows obtido de extensões Kerberos, chamadas coletivamente de S4U (Serviço para Usuário).
Representação de token armazenado em cache
Você pode executar a representação de token armazenado em cache com o seguinte:
WSHttpBinding, WSDualHttpBinding e NetTcpBinding com uma credencial de cliente do Windows.
BasicHttpBinding com um BasicHttpSecurityMode definido com a credencial TransportWithMessageCredential ou qualquer outra associação padrão em que o cliente apresenta uma credencial de nome de usuário que o serviço pode mapear para uma conta válida do Windows.
Qualquer CustomBinding que use uma credencial de cliente do Windows com
requireCancellation
definido comotrue
. (A propriedade está disponível nas seguintes classes: SecureConversationSecurityTokenParameters, SslSecurityTokenParameters e SspiSecurityTokenParameters.) Se uma conversa segura for usada na associação, também deverá ter a propriedaderequireCancellation
definida comotrue
.Qualquer CustomBinding em que o cliente apresenta uma credencial de nome de usuário. Se a conversa segura for usada na associação, também deverá ter a propriedade
requireCancellation
definida comotrue
.
Representação com base em S4U
Você pode executar a representação com base em S4U com o seguinte:
WSHttpBinding, WSDualHttpBinding e NetTcpBinding com uma credencial de cliente de certificado que o serviço pode mapear para uma conta válida do Windows.
Qualquer CustomBinding que use uma credencial de cliente do Windows com a propriedade
requireCancellation
definida comofalse
.Qualquer CustomBinding que use um nome de usuário ou uma credencial de cliente do Windows e uma conversa segura com a propriedade
requireCancellation
definida comofalse
.
A extensão em que o serviço pode representar o cliente depende dos privilégios da conta de serviço quando ela tenta representar, o tipo de representação usado e, possivelmente, a extensão de representação que o cliente permite.
Observação
Quando o cliente e o serviço estão em execução no mesmo computador e o cliente está em execução em uma conta do sistema (por exemplo, Local System
ou Network Service
), o cliente não pode ser representado quando uma sessão segura é estabelecida com tokens de Contexto de Segurança com estado. Normalmente, um aplicativo Windows Forms ou de console é executado na conta registrada no momento, para que essa conta possa ser representada por padrão. No entanto, quando o cliente é uma página ASP.NET e essa página é hospedada no IIS 6.0 ou no IIS 7.0, o cliente é executado na conta Network Service
por padrão. Todas as associações fornecidas pelo sistema que dão suporte a sessões seguras usam um SCT (token de contexto de segurança) sem estado por padrão. No entanto, se o cliente for uma página ASP.NET e sessões seguras com tokens SCT com estado forem usadas, o cliente não poderá ser representado. Para obter mais informações sobre como usar SCTs com estado em uma sessão segura, confira Como criar um token de contexto de segurança para uma sessão segura.
Representação em um método de serviço: modelo declarativo
A maioria dos cenários de representação envolve a execução do método de serviço no contexto do chamador. O WCF fornece um recurso de representação que facilita isso, permitindo que o usuário especifique o requisito de representação no atributo OperationBehaviorAttribute. Por exemplo, no código a seguir, a infraestrutura do WCF representa o chamador antes de executar o método Hello
. Qualquer tentativa de acessar recursos nativos dentro do método Hello
terá êxito somente se a ACL (lista de controle de acesso) do recurso permitir os privilégios de acesso do chamador. Para habilitar a representação, defina a propriedade Impersonation como um dos valores de enumeração ImpersonationOption ouImpersonationOption.RequiredImpersonationOption.Allowed, conforme mostrado no exemplo a seguir.
Observação
Quando um serviço tem credenciais superiores às do cliente remoto, as credenciais do serviço são usadas se a propriedade Impersonation estiver definida como Allowed. Ou seja, se um usuário de baixo privilégio fornecer suas credenciais, um serviço com privilégios mais altos executará o método com as credenciais do serviço e poderá usar recursos que o usuário de baixo privilégio não poderá usar.
[ServiceContract]
public interface IHelloContract
{
[OperationContract]
string Hello(string message);
}
public class HelloService : IHelloService
{
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public string Hello(string message)
{
return "hello";
}
}
<ServiceContract()> _
Public Interface IHelloContract
<OperationContract()> _
Function Hello(ByVal message As String) As String
End Interface
Public Class HelloService
Implements IHelloService
<OperationBehavior(Impersonation:=ImpersonationOption.Required)> _
Public Function Hello(ByVal message As String) As String Implements IHelloService.Hello
Return "hello"
End Function
End Class
A infraestrutura do WCF só poderá representar o chamador se o chamador for autenticado com credenciais que podem ser mapeadas para uma conta de usuário do Windows. Se o serviço estiver configurado para autenticação usando uma credencial que não pode ser mapeada para uma conta do Windows, o método de serviço não será executado.
Observação
No Windows XP, a representação falhará se um SCT com estado for criado, resultando em um InvalidOperationException. Para obter mais informações, confira Cenários sem suporte.
Representação em um método de serviço: modelo imperativo
Às vezes, um chamador não precisa representar todo o método de serviço para funcionar, mas apenas uma parte dele. Nesse caso, obtenha a identidade do Windows do chamador dentro do método de serviço e execute a representação de forma imperativa. Faça isso usando a propriedade WindowsIdentity do ServiceSecurityContext para retornar uma instância da classe WindowsIdentity e chamando o método Impersonate antes de usar a instância.
Observação
Use a instrução Using
do Visual Basic ou a instrução using
de C# para reverter automaticamente a ação de representação. Se você não usar a instrução, ou se usar uma linguagem de programação diferente de Visual Basic ou C#, não deixe de reverter o nível de representação. Se não fizer isso, poderá formar a base para negação de serviço e elevação de ataques de privilégios.
public class HelloService : IHelloService
{
[OperationBehavior]
public string Hello(string message)
{
WindowsIdentity callerWindowsIdentity =
ServiceSecurityContext.Current.WindowsIdentity;
if (callerWindowsIdentity == null)
{
throw new InvalidOperationException
("The caller cannot be mapped to a WindowsIdentity");
}
using (callerWindowsIdentity.Impersonate())
{
// Access a file as the caller.
}
return "Hello";
}
}
Public Class HelloService
Implements IHelloService
<OperationBehavior()> _
Public Function Hello(ByVal message As String) As String _
Implements IHelloService.Hello
Dim callerWindowsIdentity As WindowsIdentity = _
ServiceSecurityContext.Current.WindowsIdentity
If (callerWindowsIdentity Is Nothing) Then
Throw New InvalidOperationException( _
"The caller cannot be mapped to a WindowsIdentity")
End If
Dim cxt As WindowsImpersonationContext = callerWindowsIdentity.Impersonate()
Using (cxt)
' Access a file as the caller.
End Using
Return "Hello"
End Function
End Class
Representação para todos os métodos de serviço
Em alguns casos, você deve executar todos os métodos de um serviço no contexto do chamador. Em vez de habilitar explicitamente esse recurso por método, use o ServiceAuthorizationBehavior. Como mostra o código a seguir, defina a propriedade ImpersonateCallerForAllOperations como true
. ServiceAuthorizationBehavior é recuperado das coleções de comportamentos da classe ServiceHost. Observe também que a propriedade Impersonation
de OperationBehaviorAttribute aplicada a cada método também deve ser definida como Allowed ou Required.
// Code to create a ServiceHost not shown.
ServiceAuthorizationBehavior MyServiceAuthorizationBehavior =
serviceHost.Description.Behaviors.Find<ServiceAuthorizationBehavior>();
MyServiceAuthorizationBehavior.ImpersonateCallerForAllOperations = true;
' Code to create a ServiceHost not shown.
Dim MyServiceAuthorizationBehavior As ServiceAuthorizationBehavior
MyServiceAuthorizationBehavior = serviceHost.Description.Behaviors.Find _
(Of ServiceAuthorizationBehavior)()
MyServiceAuthorizationBehavior.ImpersonateCallerForAllOperations = True
A tabela a seguir descreve o comportamento do WCF para todas as combinações possíveis de ImpersonationOption
e ImpersonateCallerForAllServiceOperations
.
ImpersonationOption |
ImpersonateCallerForAllServiceOperations |
Comportamento |
---|---|---|
Obrigatório | n/d | O WCF representa o chamador |
Permitido | false | O WCF não representa o chamador |
Permitido | true | O WCF representa o chamador |
NotAllowed | false | O WCF não representa o chamador |
NotAllowed | true | Sem permissão. (Uma InvalidOperationException é lançada.) |
Nível de representação obtido de credenciais do Windows e representação de token armazenado em cache
Em alguns cenários, o cliente tem controle parcial sobre o nível de representação que o serviço executa quando uma credencial de cliente do Windows é usada. Um cenário ocorre quando o cliente especifica um nível de representação anônimo. O outro ocorre ao executar a representação com um token armazenado em cache. Isso é feito configurando a propriedade AllowedImpersonationLevel da classe WindowsClientCredential, que é acessada como uma propriedade da classe genérica ChannelFactory<TChannel>.
Observação
Especificar um nível de representação do Anônimo faz com que o cliente faça logon no serviço anonimamente. Portanto, o serviço deve permitir logons anônimos, independentemente de a representação ser executada.
O cliente pode especificar o nível de representação comoAnonymous, Identification ou Impersonation, ou Delegation. Somente um token no nível especificado é produzido, conforme mostrado no código a seguir.
ChannelFactory<IEcho> cf = new ChannelFactory<IEcho>("EchoEndpoint");
cf.Credentials.Windows.AllowedImpersonationLevel =
System.Security.Principal.TokenImpersonationLevel.Impersonation;
Dim cf As ChannelFactory(Of IEcho) = New ChannelFactory(Of IEcho)("EchoEndpoint")
cf.Credentials.Windows.AllowedImpersonationLevel = _
System.Security.Principal.TokenImpersonationLevel.Impersonation
A tabela a seguir especifica o nível de representação obtido pelo serviço ao representar de um token armazenado em cache.
AllowedImpersonationLevel valor |
O serviço tem SeImpersonatePrivilege |
O serviço e o cliente são capazes de delegar | Token armazenado em cache ImpersonationLevel |
---|---|---|---|
Anônima | Sim | n/d | Representação |
Anônima | Não | n/d | Identificação |
Identificação | n/d | n/d | Identificação |
Representação | Sim | n/d | Representação |
Representação | Não | n/d | Identificação |
Delegação | Sim | Sim | Delegação |
Delegação | Sim | No | Representação |
Delegação | Não | n/d | Identificação |
Nível de representação obtido de credenciais de nome de usuário e representação de token armazenado em cache
Ao passar ao serviço seu nome de usuário e senha, um cliente permite que o WCF faça logon como esse usuário, o que equivale a definir a propriedade AllowedImpersonationLevel
como Delegation. (A AllowedImpersonationLevel
está disponível nas classes WindowsClientCredential e HttpDigestClientCredential.) A tabela a seguir fornece o nível de representação obtido quando o serviço recebe credenciais de nome de usuário.
AllowedImpersonationLevel |
O serviço tem SeImpersonatePrivilege |
O serviço e o cliente são capazes de delegar | Token armazenado em cache ImpersonationLevel |
---|---|---|---|
n/d | Sim | Sim | Delegação |
n/d | Yes | No | Representação |
n/a | Não | n/d | Identificação |
Nível de representação obtido da representação com base em S4U
O serviço tem SeTcbPrivilege |
O serviço tem SeImpersonatePrivilege |
O serviço e o cliente são capazes de delegar | Token armazenado em cache ImpersonationLevel |
---|---|---|---|
Sim | Yes | n/d | Representação |
Sim | Não | n/d | Identificação |
Não | n/d | n/d | Identificação |
Mapeamento de um certificado do cliente para uma conta do Windows
É possível que um cliente se autentique em um serviço usando um certificado e faça com que o serviço mapeie o cliente para uma conta existente por meio do Active Directory. O XML a seguir mostra como configurar o serviço para mapear o certificado.
<behaviors>
<serviceBehaviors>
<behavior name="MapToWindowsAccount">
<serviceCredentials>
<clientCertificate>
<authentication mapClientCertificateToWindowsAccount="true" />
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
O código a seguir mostra como configurar o serviço.
// Create a binding that sets a certificate as the client credential type.
WSHttpBinding b = new WSHttpBinding();
b.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
// Create a service host that maps the certificate to a Windows account.
Uri httpUri = new Uri("http://localhost/Calculator");
ServiceHost sh = new ServiceHost(typeof(HelloService), httpUri);
sh.Credentials.ClientCertificate.Authentication.MapClientCertificateToWindowsAccount = true;
Delegação
Para delegar a um serviço de back-end, um serviço deve executar o Kerberos multi-leg (SSPI sem fallback NTLM) ou a autenticação direta Kerberos para o serviço de back-end usando a identidade do Windows do cliente. Para delegar a um serviço de back-end, crie um ChannelFactory<TChannel> e um canal e, em seguida, comunique-se por meio do canal enquanto representa o cliente. Com essa forma de delegação, a distância na qual o serviço de back-end pode ser localizado a partir do serviço front-end depende do nível de representação alcançado pelo serviço front-end. Quando o nível de representação for Impersonation, os serviços front-end e back-end deverão estar em execução no mesmo computador. Quando o nível de representação for Delegation, os serviços front-end e back-end poderão estar em computadores separados ou no mesmo computador. Habilitar a representação no nível da delegação exige que a política de domínio do Windows seja configurada para permitir a delegação. Para saber mais sobre como configurar o Active Directory para dar suporte à delegação, confira Habilitação da autenticação delegada.
Observação
Quando um cliente se autentica no serviço front-end usando um nome de usuário e uma senha que correspondem a uma conta do Windows no serviço de back-end, o serviço de front-end pode se autenticar no serviço de back-end reutilizando o nome de usuário e a senha do cliente. Essa é uma forma particularmente poderosa de fluxo de identidade, pois passar o nome de usuário e a senha para o serviço de back-end permite que o serviço execute a representação, mas não constitui delegação porque o Kerberos não é usado. Os controles do Active Directory na delegação não se aplicam à autenticação de nome de usuário e senha.
Capacidade de delegação como uma função de nível de representação
Nível de representação | O serviço pode executar a delegação entre processos | O serviço pode executar a delegação entre computadores |
---|---|---|
Identification | No | No |
Impersonation | Sim | Não |
Delegation | Sim | Sim |
O exemplo de código a seguir demonstra como usar a delegação.
public class HelloService : IHelloService
{
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public string Hello(string message)
{
WindowsIdentity callerWindowsIdentity = ServiceSecurityContext.Current.WindowsIdentity;
if (callerWindowsIdentity == null)
{
throw new InvalidOperationException
("The caller cannot be mapped to a Windows identity.");
}
using (callerWindowsIdentity.Impersonate())
{
EndpointAddress backendServiceAddress = new EndpointAddress("http://localhost:8000/ChannelApp");
// Any binding that performs Windows authentication of the client can be used.
ChannelFactory<IHelloService> channelFactory = new ChannelFactory<IHelloService>(new NetTcpBinding(), backendServiceAddress);
IHelloService channel = channelFactory.CreateChannel();
return channel.Hello(message);
}
}
}
Public Class HelloService
Implements IHelloService
<OperationBehavior(Impersonation:=ImpersonationOption.Required)> _
Public Function Hello(ByVal message As String) As String Implements IHelloService.Hello
Dim callerWindowsIdentity As WindowsIdentity = ServiceSecurityContext.Current.WindowsIdentity
If (callerWindowsIdentity Is Nothing) Then
Throw New InvalidOperationException("The caller cannot be mapped to a Windows identity.")
End If
Dim backendServiceAddress As EndpointAddress = New EndpointAddress("http://localhost:8000/ChannelApp")
' Any binding that performs Windows authentication of the client can be used.
Dim channelFactory As ChannelFactory(Of IHelloService) = _
New ChannelFactory(Of IHelloService)(New NetTcpBinding(), backendServiceAddress)
Dim channel As IHelloService = channelFactory.CreateChannel()
Return channel.Hello(message)
End Function
End Class
Como configurar um aplicativo para usar delegação restrita
Antes de usar a delegação restrita, o remetente, o receptor e o controlador de domínio devem ser configurados para fazer isso. O procedimento a seguir lista as etapas que permitem a delegação restrita. Para obter detalhes sobre as diferenças entre delegação e delegação restrita, confira a parte das Extensões Kerberos do Windows Server 2003 que discute a delegação restrita.
No controlador de domínio, desmarque a caixa de seleção Conta é confidencial e não pode ser delegada para a conta na qual o aplicativo cliente está em execução.
No controlador de domínio, marque a caixa de seleção Conta é confiável para delegação da conta na qual o aplicativo cliente está em execução.
No controlador de domínio, configure o computador de camada intermediária para que ele seja confiável para delegação, clicando na opção Confiar mo computador para delegação.
No controlador de domínio, configure o computador de camada intermediária para usar a delegação restrita, clicando na opção Confiar neste computador para delegação a serviços especificados.
Para obter instruções mais detalhadas sobre configuração da delegação restrita, confira Transição de protocolo Kerberos e delegação restrita.
Confira também
- OperationBehaviorAttribute
- Impersonation
- ImpersonationOption
- WindowsIdentity
- ServiceSecurityContext
- WindowsIdentity
- ServiceAuthorizationBehavior
- ImpersonateCallerForAllOperations
- ServiceHost
- AllowedImpersonationLevel
- WindowsClientCredential
- ChannelFactory<TChannel>
- Identification
- Utilizando Personificação com segurança de transporte
- Representando o cliente
- Como: representar um cliente em um serviço
- Ferramenta Utilitário de Metadados ServiceModel (Svcutil.exe)