Usuário com melhor resposta
Wcf Impersonate através de Domínio, Usuário e Senha!

Pergunta
-
Boa Tarde pessoal,
gostaria de realizar um Impersonate no meu serviço pois a conexão de meu banco de dados é integrated, só que, gostaria de passar os dados para que isso seja realizado, é possível?
Exemplo: Uma máquina fora do dominio, passe o dominio, usuario e senha, e eu consiga realizar o impersonate para aquele usuário para aquele serviço.
Abs
Marcel Piva
Respostas
-
Boas Marcel,
Quando você habilita o recurso de impersonation do WCF (http://www.israelaece.com/post/WCF-Seguranca.aspx), obrigatoriamente as credenciais do usuário cliente devem ser passadas para o serviço, que por sua vez, executará a operação em cima das credenciais do respectivo cliente. Mesmo que você opte por ter um maior controle do impersonation (de forma imperativa), ainda sim o usuário tem que pertencer ao seu domínio/servidor.
Agora, se você quiser validar um usuário que esteja além da sua rede, fora do domínio, então talvez poderia recorrer a API do sistema operacional, onde via PInvoke, você autentica o usuário, e se as credenciais forem válidas, faz o impersonation de forma manual, através do WindowsIdentity, assim como eu mostro aqui: http://www.israelaece.com/post/ExecutionContext.aspx. Atente-se apenas porque aquele código tem um bug, ou seja, o método Impersonate retorna a instância de uma classe chamada WindowsImpersonationContext, que representa o usuário anterior ao processo de impersonation. O ideal é que você invoque o método Undo ou envolve-lo em um bloco using, para garantir que o impersonation seja desfeito quando o processo acabar ou se alguma exceção for disparada. O exemplo fica:
IntPtr token;
if (LogonUser("Teste", "aqui é o dominio", "123456", 2, 0, out token))
{
try
{
using (WindowsIdentity.Impersonate(token))
{
//tarefas
}
}
finally
{
token = IntPtr.Zero;
}
}
Como você pode notar, isso não é nativo ao WCF. Repare que eu peguei uma parte de um artigo distinto ao WCF, mas que talvez funcione como quer. É importante que você teste.
http://www.israelaece.com- Marcado como Resposta Piva, Marcel terça-feira, 29 de setembro de 2009 23:18
-
Boas Marcel,
Como a autenticação acontece antes, quando chega no momento de executar a operação você já não deverá ter mais o contexto.
Acredito que o impersonation deve acontecer dentro da operação. Você tem a propriedade PrimaryIdentity (OperationContext.Current.ServiceSecurityContext.PrimaryIdentity) para ter acesso as credenciais do usuário atual. Você pode validar o usuário como está fazendo, ou seja, utilizando UserNamePasswordValidator através do LogonUser.
Uma vez que a autenticação retorna como verdadeira, você armazena em algum lugar o token. Com isso, dentro da operação, onde precisar da impersonation, você faz:
using(WindowsIdentity.Impersonate(AlgumObjeto.TokenDoUsuarioAutenticado))
{
//tarefas
}
http://www.israelaece.com- Marcado como Resposta Piva, Marcel quarta-feira, 30 de setembro de 2009 14:03
Todas as Respostas
-
Boas Marcel,
Quando você habilita o recurso de impersonation do WCF (http://www.israelaece.com/post/WCF-Seguranca.aspx), obrigatoriamente as credenciais do usuário cliente devem ser passadas para o serviço, que por sua vez, executará a operação em cima das credenciais do respectivo cliente. Mesmo que você opte por ter um maior controle do impersonation (de forma imperativa), ainda sim o usuário tem que pertencer ao seu domínio/servidor.
Agora, se você quiser validar um usuário que esteja além da sua rede, fora do domínio, então talvez poderia recorrer a API do sistema operacional, onde via PInvoke, você autentica o usuário, e se as credenciais forem válidas, faz o impersonation de forma manual, através do WindowsIdentity, assim como eu mostro aqui: http://www.israelaece.com/post/ExecutionContext.aspx. Atente-se apenas porque aquele código tem um bug, ou seja, o método Impersonate retorna a instância de uma classe chamada WindowsImpersonationContext, que representa o usuário anterior ao processo de impersonation. O ideal é que você invoque o método Undo ou envolve-lo em um bloco using, para garantir que o impersonation seja desfeito quando o processo acabar ou se alguma exceção for disparada. O exemplo fica:
IntPtr token;
if (LogonUser("Teste", "aqui é o dominio", "123456", 2, 0, out token))
{
try
{
using (WindowsIdentity.Impersonate(token))
{
//tarefas
}
}
finally
{
token = IntPtr.Zero;
}
}
Como você pode notar, isso não é nativo ao WCF. Repare que eu peguei uma parte de um artigo distinto ao WCF, mas que talvez funcione como quer. É importante que você teste.
http://www.israelaece.com- Marcado como Resposta Piva, Marcel terça-feira, 29 de setembro de 2009 23:18
-
-
Poxa Israel, novos problemas!!!
Seguinte....
Implementei a autenticação em minha classe MyAuthentication : UserNamePasswordValidator que está em no assembly Framework.Security chamando o LogonUser através de outra classe reservada em NativeMethods.
Quando aplico o Impersonate, tudo funciona como disse anteriormente, porém, aquele lance de realizar as tarefas e depois aplicar o Dispose não vai funcionar pra mim, pois essa classe MyAuthentication é utilizada pelo CustomCertificateValidator do WCF, pois então, após o Impersonate o meu aplicativo continua com seu fluxo até chegar a camada de acesso a dados, e então vezes ele aplica o Impersonate, vezes não aplica.
Aindei lendo a respeito e me parece que o Impersonate é realizado por Thread, e talvez por isto deva estar se perdendo, então tentei o ImpersonateLoggedOnUser também nativo e funcionou um pouqinho melhor, mas ainda está maluco, ora funciona, ora não funciona.
Tem idéia do que pode estar acontecendo ???
Abs.,
Marcel Piva -
Boas Marcel,
Qual o código que está utilizando? Dependendo, talvez algum código é executado em uma thread diferente, e o contexto de segurança não é propagado.
Não entendi quando você fala que o Dispose não vai funcionar para você.
http://www.israelaece.com -
Humm.. veja só Israel... Vou tentar expor o fluxo da chamada a uma tabela.Existe uma classe chamada ServiceHelper<T> a qual crio um proxy do meu serviço utilizando ChannelFactory, através dele, passo o Usuario e a Senha pelo factory.Credentials.UserName.UserName = "xpto" e factory.Credentials.UserName.Password = "xpto", logo a seguir é chamado o método Validate da classe MyAuthentication : UserNamePasswordValidator, para este método foi implementado o seguinte:Separei os métodos nativos em uma classe chamada NativeMethods por conta do CodeAnalisys.
IntPtr token; try { if (NativeMethods.LogonUser(userName, domain, password, 0, 2, out token) { WindowsIdentity.Impersonate(token); // Tentei também com o ImpersonateLoggedOnUser(token) // como citei no post anterior. } } finally { token = IntPtr.Zero; }
Após isto, volta para o fluxo do WCF chamando a camada de negócio que está separada em alguns projetos.Business.Facade <> Business.Components <> [DataContracts] <> DataAccessEntão em meu DataAccess ora o WindowsIdentity.GetCurrent() está com Impersonate, ora não está...Estou utilizando o DataContext para ter acesso aos dados.using (DataContext context = new DataContext("connectionstring...") { DbConnection connection = context.Connection; // Aqui é onde tenho problemas. // Ora funciona, ora não funciona a impersonificação. connection.Open(); }
PS: Talvez tenha erros nos códigos acima, fiz todo aqui no post.Abraços.
Marcel Piva -
Boas Marcel,
Como a autenticação acontece antes, quando chega no momento de executar a operação você já não deverá ter mais o contexto.
Acredito que o impersonation deve acontecer dentro da operação. Você tem a propriedade PrimaryIdentity (OperationContext.Current.ServiceSecurityContext.PrimaryIdentity) para ter acesso as credenciais do usuário atual. Você pode validar o usuário como está fazendo, ou seja, utilizando UserNamePasswordValidator através do LogonUser.
Uma vez que a autenticação retorna como verdadeira, você armazena em algum lugar o token. Com isso, dentro da operação, onde precisar da impersonation, você faz:
using(WindowsIdentity.Impersonate(AlgumObjeto.TokenDoUsuarioAutenticado))
{
//tarefas
}
http://www.israelaece.com- Marcado como Resposta Piva, Marcel quarta-feira, 30 de setembro de 2009 14:03
-
-
Bom Dia Israel.
Com meus testes aqui, armazenei uma variável estática em meu assembly Framework.Core chamada EnviromentSecurity.Token e a recupero na camada de acesso a dados.
Funcionou sem problemas...
Porém, terei diversos usuários acessando o serviço, isso será um problema não?? Pois o impersonate é no servidor e a variavel será estática e compartilhada com os usuários.
Abs
Marcel Piva -
Bom Dia Israel.
Com meus testes aqui, armazenei uma variável estática em meu assembly Framework.Core chamada EnviromentSecurity.Token e a recupero na camada de acesso a dados.
Funcionou sem problemas...
Porém, terei diversos usuários acessando o serviço, isso será um problema não?? Pois o impersonate é no servidor e a variavel será estática e compartilhada com os usuários.
Abs
Marcel Piva
Pensei em criar uma lista e armazenar o Token e o usuário e buscar o usuário nessa lista para recuperar o token. O que acha?
Marcel Piva -
Boas Marcel,
Acho que o mais ideal seria você criar um "principal/identity" próprio. Fica mais coerente.
Repare neste artigo: http://www.israelaece.com/post/WCF-Seguranca-Autenticacao-e-Autorizacao-Customizadas.aspx
Note que eu criei um XmlIdentity/XmlPrincipal e depois você "pluga" através do IAuthorizationPolicy. Você pode tentar aplicar as mesmas técnicas para "plugar" o que precisa.
http://www.israelaece.com -
Israel,
eu tenho meu Identity e Principal implementados, porém, acho que terei problemas em disponibilizar a aplicação via ClickOnce para X tipos de sistemas operacionais por conta da utilização da API do Windows.
O Identity e Principal estão implementados em Framework.Security. (Client/Server)
E o restante referente ao WCF está em Framework.WCF.Security (Server)
Marcel Piva -
-
Utilizo o IIdetntiy/IPrincipal em ambos lados Client/Server, não devo deixar o consumo da API (LogonUser) do lado do cliente.
Então, botei isso na geladeira por enquanto, voltarei a ver isso depois, preciso dar andamento aqui.
Darei mais detalhes depois.
Obrigado pela força por enquanto.
[]s
Marcel Piva