<commit_before>﻿using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace ConDep.Dsl.Impersonation
{
    public class Impersonator : IDisposable
    {
        private readonly string _username;
        private readonly string _password;
        private readonly string _domain;
        private bool _disposed = false;
        private IntPtr _tokenDuplicate;
        private WindowsImpersonationContext _impersonationContext;
        private IntPtr _token;

        public Impersonator(string username, string password)
        {
            _username = GetUserName(username);
            _domain = GetDomain(username);
            _password = password;

            try
            {
                Initialize();
            }
            catch
            {
                Dispose();
                throw;
            }
        }

        public static string GetUserName(string username)
        {
            var split = username.Split('\\');
            if (split.Length == 1)
            {
                return username;
            }
            if (split.Length == 2)
            {
                return split[1];
            }
            throw new NotSupportedException("Username format not supported. More than one '\\' found in username string.");
        }

        public static string GetDomain(string username)
        {
            var split = username.Split('\\');
            if (split.Length == 1)
            {
                return "";
            }
            if (split.Length == 2)
            {
                return split[0];
            }
            throw new NotSupportedException("Username format not supported. More than one '\\' found in username string.");
        }

        private void Initialize()
        {
            if (!NativeMethods.LogonUser(
                _username,
                _domain,
                _password,
                NativeMethods.LogonType.NetworkCleartext,//.NewCredentials,
                NativeMethods.LogonProvider.Default,
                out _token))
            {
                throw new Win32Exception();
            }

            if (!NativeMethods.DuplicateToken(
                _token,
                NativeMethods.SecurityImpersonationLevel.Impersonation,
                out _tokenDuplicate))
            {
                throw new Win32Exception();
            }

            _impersonationContext = new WindowsIdentity(_tokenDuplicate).Impersonate();
                // Do stuff with your share here.
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called. 
            if (!_disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources. 
                if (disposing)
                {
                    _impersonationContext.Undo();
                    _impersonationContext.Dispose();

                    if (_tokenDuplicate != IntPtr.Zero)
                    {
                        if (!NativeMethods.CloseHandle(_tokenDuplicate))
                        {
                            // Uncomment if you need to know this case.
                            ////throw new Win32Exception();
                        }
                    }

                    if (_token != IntPtr.Zero)
                    {
                        if (!NativeMethods.CloseHandle(_token))
                        {
                            // Uncomment if you need to know this case.
                            ////throw new Win32Exception();
                        }
                    }

                }

                _disposed = true;

            }
        }

        ~Impersonator()
        {
            Dispose(false);
        }
    }

    /// <summary>
    /// Implements P/Invoke Interop calls to the operating system.
    /// </summary>
    internal static class NativeMethods
    {
        /// <summary>
        /// The type of logon operation to perform.
        /// </summary>
        internal enum LogonType : int
        {
            /// <summary>
            /// This logon type is intended for users who will be interactively
            /// using the computer, such as a user being logged on by a
            /// terminal server, remote shell, or similar process.
            /// This logon type has the additional expense of caching logon<commit_msg>Added check for empty username/password on impersonation.<commit_after>﻿using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace ConDep.Dsl.Impersonation
{
    public class Impersonator : IDisposable
    {
        private readonly string _username;
        private readonly string _password;
        private readonly string _domain;
        private bool _disposed = false;
        private IntPtr _tokenDuplicate;
        private WindowsImpersonationContext _impersonationContext;
        private IntPtr _token;

        public Impersonator(string username, string password)
        {
            if (username == null || password == null)
                return;

            _username = GetUserName(username);
            _domain = GetDomain(username);
            _password = password;

            try
            {
                Initialize();
            }
            catch
            {
                Dispose();
                throw;
            }
        }

        public static string GetUserName(string username)
        {
            var split = username.Split('\\');
            if (split.Length == 1)
            {
                return username;
            }
            if (split.Length == 2)
            {
                return split[1];
            }
            throw new NotSupportedException("Username format not supported. More than one '\\' found in username string.");
        }

        public static string GetDomain(string username)
        {
            var split = username.Split('\\');
            if (split.Length == 1)
            {
                return "";
            }
            if (split.Length == 2)
            {
                return split[0];
            }
            throw new NotSupportedException("Username format not supported. More than one '\\' found in username string.");
        }

        private void Initialize()
        {
            if (!NativeMethods.LogonUser(
                _username,
                _domain,
                _password,
                NativeMethods.LogonType.NetworkCleartext,//.NewCredentials,
                NativeMethods.LogonProvider.Default,
                out _token))
            {
                throw new Win32Exception();
            }

            if (!NativeMethods.DuplicateToken(
                _token,
                NativeMethods.SecurityImpersonationLevel.Impersonation,
                out _tokenDuplicate))
            {
                throw new Win32Exception();
            }

            _impersonationContext = new WindowsIdentity(_tokenDuplicate).Impersonate();
                // Do stuff with your share here.
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called. 
            if (!_disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources. 
                if (disposing)
                {
                    if(_impersonationContext != null)
                    {
                        _impersonationContext.Undo();
                        _impersonationContext.Dispose();
                    }

                    if (_tokenDuplicate != IntPtr.Zero)
                    {
                        if (!NativeMethods.CloseHandle(_tokenDuplicate))
                        {
                            // Uncomment if you need to know this case.
                            ////throw new Win32Exception();
                        }
                    }

                    if (_token != IntPtr.Zero)
                    {
                        if (!NativeMethods.CloseHandle(_token))
                        {
                            // Uncomment if you need to know this case.
                            ////throw new Win32Exception();
                        }
                    }
                }

                _disposed = true;

            }
        }

        ~Impersonator()
        {
            Dispose(false);
        }
    }

    /// <summary>
    /// Implements P/Invoke Interop calls to the operating system.
    /// </summary>
    internal static class NativeMethods
    {
        /// <summary>
        /// The type of logon operation to perform.
        /// </summary>
        internal enum LogonType : int
        {
            /// <summary>
            /// This logon type is intended for users who will be interactively
            /// using the computer, such as a user being logged on by a
            /// terminal server, remote shell, or similar process.
            /// This logon type has the additional expense of caching logon
{'fraction_non_alphanumeric': 0.07544973544973545, 'fraction_numerical': 0.002962962962962963, 'mean_word_length': 1.1503981797497156, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4541101', 'n_tokens_mistral': 2180, 'n_tokens_neox': 2041, 'n_words': 589}