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

namespace ClipSoft.Utility
{
    public class ImpersonationUtility
    {
        ///////////////////////////////////////////////////////////////////////
        // Impersonate Method : BasePage에서 내용을 Copy함
        ///////////////////////////////////////////////////////////////////////
        #region Impersonation

        /// <summary>
        /// LogonUser정보처리
        /// </summary>
        /// <param name="lpszUsername">lpszUsername</param>
        /// <param name="lpszDomain">lpszDomain</param>
        /// <param name="lpszPassword">lpszPassword</param>
        /// <param name="dwLogonType">dwLogonType</param>
        /// <param name="dwLogonProvider">dwLogonProvider</param>
        /// <param name="phToken">phToken</param>
        /// <returns>bool</returns>
        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
            int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        /// <summary>
        /// CloseHandle
        /// </summary>
        /// <param name="handle">handle</param>
        /// <returns>bool</returns>
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr handle);
        /// <summary>
        /// DuplicateToken
        /// </summary>
        /// <param name="ExistingTokenHandle">ExistingTokenHandle</param>
        /// <param name="SECURITY_IMPERSONATION_LEVEL">SECURITY_IMPERSONATION_LEVEL</param>
        /// <param name="DuplicateTokenHandle">DuplicateTokenHandle</param>
        /// <returns>bool</returns>
        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool DuplicateToken(IntPtr ExistingTokenHandle,
            int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

        WindowsImpersonationContext _imp_user;

        /// <summary>
        /// Impersonation을 실행합니다. 
        /// </summary>
        /// <param name="domain">도메인</param>
        /// <param name="userid">사용자아이디</param>
        /// <param name="pwd">비밀번호</param>
        /// <returns></returns>
        public bool ImpersonationStart(string myDomain, string userid, string pwd)
        {
            try
            {
                IntPtr token = IntPtr.Zero;
                IntPtr dupe_token = IntPtr.Zero;
                string domain = myDomain;
                string user_id = userid;
                string password = pwd;
                WindowsIdentity ident = null;

                int error_code = 0;

                bool result = LogonUser(user_id, domain, password, 2, 0, ref token);

                if (!result)
                {
                    error_code = Marshal.GetLastWin32Error();
                    throw new Exception("Impersonation 로그인 실패 하였습니다. 오류코드 ->" + Convert.ToString(error_code));
                }

                result = DuplicateToken(token, 2, ref dupe_token);

                if (!result)
                {
                    CloseHandle(token);
                    throw new Exception("Impersonation Duplicate시 오류가 발생하였습니다.");
                }

                ident = new WindowsIdentity(dupe_token);

                _imp_user = ident.Impersonate();
                return true;
            }
            catch (Exception ex)
            { }
            return false;
        }

        /// <summary>
        /// Impersonation을 종료합니다. 
        /// </summary>
        public void ImpersonationEnd()
        {
            if (_imp_user != null)
                _imp_user.Undo();
        }

        #endregion
    }

}
