Wednesday, April 6, 2011

Sử dụng Impersonation để truy cập tài nguyên trong mạng

Với các ứng dụng cần thực hiện truy cập và sử dụng đến các tài nguyên có trong hệ thống  mạng nội bộ hoặc VPN (ví dụ như đọc/ghi file vào thư mục sharing trên serrver). Nếu ứng dụng của bạn chạy trong cùng một Domain và sử dụng Windows Authentication thì việc thiết lập này khá đơn giản.

Tuy nhiên, có thể trong một hệ thống mạng có nhiều Domain khác nhau, thì đoạn code sau sẽ giúp bạn làm việc sử dụng các tài nguyên không cùng trong Domain bằng user account được phân quyền truy cập (đọc/ghi/..) vào Domain đó.
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;

namespace Security
{
    public enum LogonType : int
    {
        LOGON32_LOGON_INTERACTIVE = 2,
        LOGON32_LOGON_NETWORK = 3,
        LOGON32_LOGON_BATCH = 4,
        LOGON32_LOGON_SERVICE = 5,
        LOGON32_LOGON_UNLOCK = 7,
        LOGON32_LOGON_NETWORK_CLEARTEXT = 8, // Only for Win2K or higher
        LOGON32_LOGON_NEW_CREDENTIALS = 9 // Only for Win2K or higher
    } ;

    public enum LogonProvider : int
    {
        LOGON32_PROVIDER_DEFAULT = 0,
        LOGON32_PROVIDER_WINNT35 = 1,
        LOGON32_PROVIDER_WINNT40 = 2,
        LOGON32_PROVIDER_WINNT50 = 3
    } ;

    internal class SecureUtil32
    {
        [DllImport("advapi32.dll", SetLastError=true)]
        public static extern bool LogonUser(
            String lpszUsername, String lpszDomain, String lpszPassword,
            int dwLogonType, int dwLogonProvider, ref IntPtr TokenHandle);

        [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr handle);

        [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
        public static extern bool DuplicateToken(
            IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, 
            ref IntPtr DuplicateTokenHandle);
    }

    public class ImpersonateUser : IDisposable
    {
        private static IntPtr tokenHandle = new IntPtr(0);
        
        private 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)
        {
            m_UserName = userName;

            tokenHandle = IntPtr.Zero;
            
            // ---- Step - 1
            // Call LogonUser to obtain a handle to an access token.
            bool returnValue = SecureUtil32.LogonUser(
                userName,
                domainName,
                password,
                (int)LogonType.LOGON32_LOGON_NEW_CREDENTIALS,
                (int)LogonProvider.LOGON32_PROVIDER_DEFAULT,
                ref tokenHandle); // tokenHandle - new security token
                
            if (false == returnValue)
            {
                impersonatedUser = null;
                return;
                //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()
        {
            if (string.IsNullOrEmpty(m_UserName))
                return;

            if (impersonatedUser != null)
                impersonatedUser.Undo();
            // Free the tokens.
            if (tokenHandle != IntPtr.Zero)
                SecureUtil32.CloseHandle(tokenHandle);
        }

        #region IDisposable Members
        public void Dispose()
        {
            Undo();
        }
        #endregion
    }
}
Và phương pháp sử dụng sẽ như dưới đây:
using (ImpersonateUser imp = new ImpersonateUser())
{
    imp.Impersonate(domainName, userName, password);

    //Code truy cập tài nguyên trong hệ thống ở đây
}
Hy vọng đoạn code sẽ giúp ích được bạn trong việc giải quyết các vấn đề của mình.

No comments:

Post a Comment