web-dev-qa-db-fra.com

Comment utiliser correctement LogonUser pour emprunter l'identité d'un utilisateur de domaine à partir du client du groupe de travail

ASP.NET: emprunter l'identité d'un domaine sur VMWare

Cette question est ce que je demande, mais la réponse ne fournit pas de détails sur la façon dont le _token est dérivé. Il semble n'utiliser que WindowsIdentity.GetCurrent().Token, il n'y a donc pas d'usurpation d'identité.

Puis-je emprunter l'identité d'un utilisateur sur un autre domaine Active Directory dans .NET?

La question suivante a des réponses contradictoires, la réponse acceptée portant le commentaire "Je commence à soupçonner que mon problème est ailleurs". Inutile.

LogonUser ne fonctionne que pour mon domaine

Cette question suivante semble impliquer que ce n'est pas possible, mais elle traite de deux domaines et je ne suis donc pas sûr que ce soit pertinent.

Ma vraie question est:

  • C'est possible? Et si oui,
  • Comment? ou Où est-ce que je me suis trompé?

Ce que j’ai essayé jusqu’à présent, c’est d’utiliser le code de http://msdn.Microsoft.com/en-us/library/chf6fbt4%28v=VS.80%29.aspx

bool returnValue = LogonUser(user, domain, password,
            LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT,
            ref tokenHandle);
// after this point, returnValue = false

L'erreur Win32 est

Échec d'ouverture de session: nom d'utilisateur inconnu ou mot de passe incorrect

39
RichardTheKiwi

Très peu de publications suggèrent d'utiliser LOGON_TYPE_NEW_CREDENTIALS au lieu de LOGON_TYPE_NETWORK ou LOGON_TYPE_INTERACTIVE. J'ai eu un problème d'usurpation d'identité avec une machine connectée à un domaine et non pas, ce qui a été corrigé ... Le dernier fragment de code dans ce message suggère que l'usurpation d'identité dans une forêt fonctionne, mais cela ne s'applique pas spécifiquement. ne rien dire sur la confiance qui est mise en place. Donc, cela peut valoir la peine d'essayer:

const int LOGON_TYPE_NEW_CREDENTIALS = 9;
const int LOGON32_PROVIDER_WINNT50 = 3;
bool returnValue = LogonUser(user, domain, password,
            LOGON_TYPE_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50,
            ref tokenHandle);

MSDN dit que LOGON_TYPE_NEW_CREDENTIALS ne fonctionne que lorsque LOGON32_PROVIDER_WINNT50 est utilisé.

55
takrl

cela fonctionne pour moi, exemple complet (je souhaite que plus de gens le fassent)

//logon impersonation
using System.Runtime.InteropServices; // DllImport
using System.Security.Principal; // WindowsImpersonationContext
using System.Security.Permissions; // PermissionSetAttribute

...

class Program {

    // obtains user token
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
        int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

    // closes open handes returned by LogonUser
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public extern static bool CloseHandle(IntPtr handle);

    public void DoWorkUnderImpersonation() {
        //elevate privileges before doing file copy to handle domain security
        WindowsImpersonationContext impersonationContext = null;
        IntPtr userHandle = IntPtr.Zero;
        const int LOGON32_PROVIDER_DEFAULT = 0;
        const int LOGON32_LOGON_INTERACTIVE = 2;
        string domain = ConfigurationManager.AppSettings["ImpersonationDomain"];
        string user = ConfigurationManager.AppSettings["ImpersonationUser"];
        string password = ConfigurationManager.AppSettings["ImpersonationPassword"];

        try {
            Console.WriteLine("windows identify before impersonation: " + WindowsIdentity.GetCurrent().Name);

            // if domain name was blank, assume local machine
            if (domain == "")
                domain = System.Environment.MachineName;

            // Call LogonUser to get a token for the user
            bool loggedOn = LogonUser(user,
                                        domain,
                                        password,
                                        LOGON32_LOGON_INTERACTIVE,
                                        LOGON32_PROVIDER_DEFAULT,
                                        ref userHandle);

            if (!loggedOn) {
                Console.WriteLine("Exception impersonating user, error code: " + Marshal.GetLastWin32Error());
                return;
            }

            // Begin impersonating the user
            impersonationContext = WindowsIdentity.Impersonate(userHandle);

            Console.WriteLine("Main() windows identify after impersonation: " + WindowsIdentity.GetCurrent().Name);

            //run the program with elevated privileges (like file copying from a domain server)
            DoWork();

        } catch (Exception ex) {
            Console.WriteLine("Exception impersonating user: " + ex.Message);
        } finally {
            // Clean up
            if (impersonationContext != null) {
                impersonationContext.Undo();
            }

            if (userHandle != IntPtr.Zero) {
                CloseHandle(userHandle);
            }
        }
    }


    private void DoWork() {
        //everything in here has elevated privileges

        //example access files on a network share through e$ 
        string[] files = System.IO.Directory.GetFiles(@"\\domainserver\e$\images", "*.jpg");
    }
}
18
JJ_Coder4Hire

J'avais le même problème. Je ne sais pas si vous avez résolu ce problème ou non, mais ce que j'essayais réellement de faire était d'accéder à un partage réseau avec des informations d'identification AD. WNetAddConnection2() est ce que vous devez utiliser dans ce cas.

1
Conrad

J'ai réussi à emprunter l'identité d'utilisateurs dans un autre domaine, mais seulement avec une relation de confiance établie entre les 2 domaines.

var token = IntPtr.Zero;
var result = LogonUser(userID, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token);
if (result)
{
    return WindowsIdentity.Impersonate(token);
}
1
Jason

Un login/mot de passe invalide pourrait également être lié à des problèmes sur votre serveur DNS - c'est ce qui m'est arrivé et m'a coûté 5 bonnes heures de ma vie. Voyez si vous pouvez spécifier l'adresse IP à la place du nom de domaine.

0
Dan

Mieux vaut utiliser un SecureString:

var password = new SecureString();
var phPassword phPassword = Marshal.SecureStringToGlobalAllocUnicode(password);
IntPtr phUserToken;
LogonUser(username, domain, phPassword, LOGON32_LOGON_INTERACTIVE,  LOGON32_PROVIDER_DEFAULT, out phUserToken);

Et:

Marshal.ZeroFreeGlobalAllocUnicode(phPassword);
password.Dispose();

Définition de la fonction:

private static extern bool LogonUser(
  string pszUserName,
  string pszDomain,
  IntPtr pszPassword,
  int dwLogonType,
  int dwLogonProvider,
  out IntPtr phToken);
0
Tovich