Search code examples
c#wpfimpersonation

Check current user credentials in debug mode in a wpf application


I am trying to run an application that would be able to stop and start a service remotely. The application needs to be able to be used by users without admin privileges by Impersonating a user which username, password and domain are read from the encrypted database.

The problem which I'm currently facing is that I'm not sure if the Impersonate function is working correctly, hence why I want to check in debug mode which user is current.

This is the class I use to Impersonate a user:

using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.Security.Permissions;

public class ImpersonateUser
{
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool LogonUser(
    String lpszUsername,
    String lpszDomain,
    String lpszPassword,
    int dwLogonType,
    int dwLogonProvider,
    ref IntPtr phToken);
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public extern static bool CloseHandle(IntPtr handle);
    private static IntPtr tokenHandle = new IntPtr(0);
    private static WindowsImpersonationContext impersonatedUser;
    // If you incorporate this code into a DLL, be sure to demand that it
    // runs with FullTrust.
    [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    public void Impersonate(string domainName, string userName, string password)
    {
        //try
        {
            // Use the unmanaged LogonUser function to get the user token for
            // the specified user, domain, and password.
            const int LOGON32_PROVIDER_DEFAULT = 0;
        // Passing this parameter causes LogonUser to create a primary token.
        const int LOGON32_LOGON_INTERACTIVE = 2;
        tokenHandle = IntPtr.Zero;
        // ---- Step - 1
        // Call LogonUser to obtain a handle to an access token.
        bool returnValue = LogonUser(
        userName,
        domainName,
        password,
        LOGON32_LOGON_INTERACTIVE,
        LOGON32_PROVIDER_DEFAULT,
        ref tokenHandle); // tokenHandle - new security token
        if (false == returnValue)
        {
            int ret = Marshal.GetLastWin32Error();
            throw new System.ComponentModel.Win32Exception(ret);
        }
        // ---- Step - 2
        WindowsIdentity newId = new WindowsIdentity(tokenHandle);
        // ---- Step - 3
        {
            impersonatedUser = newId.Impersonate();
        }
    }
}
// Stops impersonation
public void Undo()
{
    impersonatedUser.Undo();
    // Free the tokens.
    if (tokenHandle != IntPtr.Zero)
    {
        CloseHandle(tokenHandle);
    }            
}        

}

This is how I'm trying to use it:

ImpersonateUser iu = new ImpersonateUser();
iu.Impersonate("[domain]","[username]","[password]");

try{
    ServiceController service = new ServiceController(serviceName, remoteComputer);
    service.Start();
}

iu.Undo(); 

But I'm not sure if the code I insert is ok or I should add something else when I'm writing the code.


Solution

  • I found what I was looking for and it's a simple call to WindowsIdentity.GetCurrent().Name; Where the return is the user currently using the application and like in my case you're using Impersonate() you will need to pass a boolean to the call like so: WindowsIdentity.GetCurrent(true).Name; Whih will return the impersonated user.

    EDIT

    Also I would like to add something for other people who may be facing the same problems that since I was trying to check the privileges of the User on a remote machine this didn't quite do the trick. That's why I used another function

    static bool isAdmin(string username, string machinename)
    {
    using (PrincipalContext ctxMacine = new PrincipalContext(ContextType.Machine, machinename))
    {
        using (PrincipalContext ctxDomain = new PrincipalContext(ContextType.Domain))
        {
            UserPrincipal up = UserPrincipal.FindByIdentity(ctxDomain, IdentityType.SamAccountName, username);
            GroupPrincipal gp = GroupPrincipal.FindByIdentity(ctxMacine, "Administrators");
    
            foreach (UserPrincipal usr in gp.GetMembers(true))
            {
                if (up != null)
                {
                    if (up.SamAccountName.ToUpper() == usr.SamAccountName.ToUpper())
                    {
                        return true;
                    }
                }
            }
        }
    }
    return false;
    

    }

    Which when used like this:

     ImpersonateUser iu = new ImpersonateUser();
            iu.Impersonate(domain, userName, password);
    
    string name = WindowsIdentity.GetCurrent(true).Name;
    MessageBox.Show("CurrentUser: " + name + " " + isAdmin(name, remoteComputer));
    
    iu.Undo();
    

    Will tell you if the current User you're Impersonating has Administrator privileges on the remoteComputer you're trying to access.