LogonUser e delegação
-
13-09-2019 - |
Pergunta
Eu estou usando a API LogonUser Win32:
token = LogonUser(...)
WindowsIdentity newId = new WindowsIdentity(token);
WindowsImpersonationContext impersonatedUser = newId.Impersonate();
No entanto, quando chamar um serviço WCF depois disso, eu não sou capaz de usar a identidade representada. Eu acho que isso é porque impersonatedUser.ImpersonationLevel igual representação.
Esta é a razão? É um nível de ImpersonationLevel.Identification o que eu preciso? Como chegar a um tal nível?
Solução
Eu não sei se isso vai funcionar para WCF. Mas nós usá-lo em nosso aplicativo web de produção para representação de ler e arquivos de gravação para o sistema de arquivos. Você precisará definir a API é para AdvApi32.LogonUser, AdvApi32.DuplicateToken e Kernel32.CloseHandle e certifique-se para fechar a WindowsImpersonationContext quando você está feito.
/// <summary>impersonates a user</summary>
/// <param name="username">domain\name of the user account</param>
/// <param name="password">the user's password</param>
/// <returns>the new WindowsImpersonationContext</returns>
public static WindowsImpersonationContext ImpersonateUser(String username, String password)
{
WindowsIdentity winId = WindowsIdentity.GetCurrent();
if (winId != null)
{
if (string.Compare(winId.Name, username, true) == 0)
{
return null;
}
}
//define the handles
IntPtr existingTokenHandle = IntPtr.Zero;
IntPtr duplicateTokenHandle = IntPtr.Zero;
String domain;
if (username.IndexOf("\\") > 0)
{
//split domain and name
String[] splitUserName = username.Split('\\');
domain = splitUserName[0];
username = splitUserName[1];
}
else
{
domain = String.Empty;
}
try
{
//get a security token
bool isOkay = AdvApi32.LogonUser(username, domain, password,
(int) AdvApi32.LogonTypes.LOGON32_LOGON_INTERACTIVE,
(int) AdvApi32.LogonTypes.LOGON32_PROVIDER_DEFAULT,
ref existingTokenHandle);
if (!isOkay)
{
int lastWin32Error = Marshal.GetLastWin32Error();
int lastError = Kernel32.GetLastError();
throw new Exception("LogonUser Failed: " + lastWin32Error + " - " + lastError);
}
// copy the token
isOkay = AdvApi32.DuplicateToken(existingTokenHandle,
(int) AdvApi32.SecurityImpersonationLevel.SecurityImpersonation,
ref duplicateTokenHandle);
if (!isOkay)
{
int lastWin32Error = Marshal.GetLastWin32Error();
int lastError = Kernel32.GetLastError();
Kernel32.CloseHandle(existingTokenHandle);
throw new Exception("DuplicateToken Failed: " + lastWin32Error + " - " + lastError);
}
// create an identity from the token
WindowsIdentity newId = new WindowsIdentity(duplicateTokenHandle);
WindowsImpersonationContext impersonatedUser = newId.Impersonate();
return impersonatedUser;
}
finally
{
//free all handles
if (existingTokenHandle != IntPtr.Zero)
{
Kernel32.CloseHandle(existingTokenHandle);
}
if (duplicateTokenHandle != IntPtr.Zero)
{
Kernel32.CloseHandle(duplicateTokenHandle);
}
}
}
Outras dicas
depois disso, eu não sou capaz de usar o identidade representada
A representação deve ser eficaz para o acesso na mesma caixa, mas não na rede.
Pode ser, como mostra o código de consultutah, que você só precisa chamar DuplicateToken (), a fim de converter o logon token para uma representação simbólica antes que possa ser utilizado.
Eu acho que isso é porque impersonatedUser.ImpersonationLevel igual representação.
Se você precisa agir como o usuário representado a outros sistemas, você precisa de um maior nível de representação chamada 'delegação'. Este é basicamente equivalente a ter a senha do usuário para que possa representar a si mesmo como a outros.