Impersonation é uma técnica utilizada para executar determinada tarefa em seu trecho de código sob uma conta de usuário específica, por exemplo imagine que necessita acessar determinada pasta e escrever um arquivo qualquer, porém somente uma conta de usuário específica tem permissão para executar esta tarefa, ou acessar determinada pasta de rede através de um compartilhamento, utilizando conta de usuário específica, ou até mesmo iniciar alguma tarefa do sistema através de um processo.

Bem agora vamos lá.

Primeiro precisamos importar dois métodos do sistema operacional, para que possamos obter o token de acesso. Para tal iremos importar as dll advapi32.dll e kernel32.dll

Nesse método iremos obter o token de acesso do sistema.

[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int DuplicateToken(IntPtr hToken, int impersionateLevel, ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool RevertToSelf();
[DllImport("kernel32.dll")]
public static extern bool CloseHandle(IntPtr token);

RevertToSelf, irá terminar a representação ativada no momento na aplicação cliente.
DuplicateToken, como o nome já diz irá duplicar o token obtido através da função LogonUser. Porque precisamos criar um impersonation token.
Um impersonation token irá capturar as informações de segurança do processo cliente permitindo ao servidor representar o cliente em operações de segurança.
Veja que o número mágico 2 em DuplicateToken é o nível de segurança no qual iremos duplicar o token 2 – SecurityImpersonation.
SecurityImpersonation – O servidor pode representar o contexto de segurança do cliente em seu sistema local o servidor não pode representar o cliente em sistemas remotos.

Vamos ver os tipos de logon que podemos utilizar e o que mais se aplica a nossa operação:

LOGON32_LOGON_INTERACTIVE = 2
Este tipo de supõe que o usuário estará interagindo com o computador através de terminal remoto, shell ou processos similares, este tipo de logon é inapropriado para aplicações cliente/servidor.

LOGON32_LOGON_NETWORK = 3
Este tipo de logon é destinado a servidores de alta performance.


LOGON32_LOGON_BATCH = 4
Este tipo de logon é destinado a execução de processos Batch, os processos são executados sem a intervenção de usuário, pode ser utilizado com serviços de e-mail ou web server.

LOGON32_LOGON_SERVICE = 5
Indica que é um logon do tipo service, porém deve ter permissão de serviço liberada no AD.

LOGON32_LOGON_UNLOCK = 7
Este tipo de logon deve ser utilizado com o usuário conectado ao computador onde será executada a tarefa, pode gerar log de auditoria.

LOGON32_LOGON_NETWORK_CLEARTEXT = 8
Este tipo de logon preserva o usuário e senha, permitindo que através deste usuário possa realizar a conexão com outra máquinas da rede.

LOGON32_LOGON_NEW_CREDENTIALS = 9
Este tipo de logon permite clonar o token corrente e criar novas credenciais.

Agora vamos ver o que interessa O CÓDIGO.

using System;
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.ComponentModel;

public class Impersionator : IDisposable
{
private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;
private const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
private WindowsImpersonationContext impersonationContext = null;

public Impersionator(string userName, string domainName, string password)
{
ImpersionateValidUser(userName, domainName, password);
}
public void Dispose()
{
UndoImpersionation();
}
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int LogonUser(string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int DuplicateToken(IntPtr hToken, int impersionateLevel, ref IntPtr hNewToken);

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool RevertToSelf();

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool CloseHandle(IntPtr handle);

private void ImpersionateValidUser(string userName, string domainName, string password)
{
WindowsIdentity tempWindowsIdentity = null;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
try
{
if(RevertToSelf())
{
if(LogonUser(userName, domainName, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
if(DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
if (token != IntPtr.Zero)
CloseHandle(token);
if (tokenDuplicate != IntPtr.Zero)
CloseHandle(tokenDuplicate);
}
}
private void UndoImpersionation()
{
if (impersonationContext != null)
impersonationContext.Undo();
}
}

Para utilizar a classe basta realizar a chamada quando conveniente em seu código.

using (new Impersionator(ssUserName, ssDomain, ssPassword))
{
//seu código aqui
}

E assim temos no impersonation implementado, espero ter contribuído para sua implementação, ficamos assim, até a próxima 🙂

Referências:
[1] https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-duplicatetoken
[2] https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ne-winnt-_security_impersonation_level




Willian Cristopher Filus

Developer

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *