Tuesday, June 17, 2014

C# - Impersonator Beispiel


Ich denke es war schon jeder einmal an diesem Punkt ... Eine Applikation soll Laufwerkszugriffe (kopieren, löschen, umbenennen, etc) ausführen, jedoch sollen die User selbst keinen Zugriff auf das Laufwerk haben.
Wie soll dieses Problem gelöst werden? :-(

Die Antwort könnte sein, einen speziellen Account innerhalb der Applikation zu verwenden.

Ich habe diese Problemstellung wie folgt gelöst:


1) Erstellen einer neuen Klasse "Impersonator"

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


namespace Test.Impersonator

{
    public class Impersonator : IDisposable
    {
        public Impersonator(string userName, string domainName, string password)
        {
            ImpersonateValidUser(userName, domainName, password);
        }

        public void Dispose()
        {
            UndoImpersonation();
        }

        [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 impersonationLevel, 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 const int LOGON32_LOGON_INTERACTIVE = 2;
        private const int LOGON32_PROVIDER_DEFAULT = 0;

        private void ImpersonateValidUser(string userName, string domain, string password)
        {
            WindowsIdentity tempWindowsIdentity = null;
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;

            try
            {
                if (RevertToSelf())
                {
                    if (LogonUser(userName, domain, 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 UndoImpersonation()
        {
            if (impersonationContext != null)
            {
                impersonationContext.Undo();
            }
        }

        private WindowsImpersonationContext impersonationContext = null;
    }
}



2) Um die Impersonator Klasse im Hauptprogramm verwenden zu können, muss diese einfach um den Block welcher als anderer User ausgeführt werden soll eingebaut werden.

using...
using Test.Impersonator;
namespace Test
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        private void StartDataTransfer()
        {

              //Do something as User1
            using (new Impersonator("UserName", "Domain", "Password"))
            {

                     //Do something as User2
            }
        }

    }
}
  


Für Fragen oder Anregungen einfach kommentieren :-)

No comments:

Post a Comment