CAFE

회원닷넷공부방

[C#][알아두면 좋은팁 #2] Impersonate

작성자채원아빠|작성시간08.07.30|조회수508 목록 댓글 0

알아두면 좋은팁 그 두번째 Impersonate 입니다.

 

발생시나리오

 - NAS 장비에 이미지를 공유를 통해 올리고, 별도의 도메인으로 서비스 되도록 한다.

 - 웹 사이트는 네트워크 서비스 계정으로 돌아가며, NAS 장비 공유의 계정은 별도로 받았다.

 

1차 꼼수처리

 - 웹 사이트 구성할때 네트워크 서비스 계정을 사용하지 않고, 별도로 받은 NAS 장비 계정으로 사이트를 만든다.

 - ;;;;;;;

 

아무래도 안되겠다.

 - 뭔가 마음이 놓이질 않는다. 그럴리야 없겠지만, 보안상 문제가 생기지는 않을까? ㅡㅡ;

 - 뭔가 양껏 불안하다 ;; 결국 구글링

 - Impersonate 라는 것을 찾았다.

 

Impersonate 란

 - 네트워크 서비스 계정 -> NTFS 권한을 가진 계정으로 실행할 수 있도록 Windows API 를 사용하여 변경 -> 다시 네트워크 서비스 계정

 - 네트워크 서비스 계정은 사이트 일때 이고, C# 어플리케이션이나 C/S 시스템에선 다를 수 있겠죵~

 - 뭐 결국은 Windows API로 실행 계정을 변경 했다가 다시 돌린다는 것입니다.

 

이하 아래는 제가 사용한 Impersonate 클래스 소스 원본 입니다. 파란색 글은 설명 입니다. ^^;

============================================= 아 래. =============================================

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

 

namespace Test.Impersonate // 네임스페이스를 알맞게... ^^;
{

// region 구문은 API에 사용할 변수들을 선언 합니다. 뭔지는 잘 모릅니다. 여튼 없으믄 안됩니다. ;;
 #region LogonType, LogonProvider

 /// <summary>
 /// LogonUser API에서 사용하는 로그온 타입
 /// </summary>
 public enum LogonType
 {
  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,
  LOGON32_LOGON_NEW_CREDENTIALS = 9
 }

 /// <summary>
 /// LogonUser API에서 사용하는 로그온 프로바이더
 /// </summary>
 public enum LogonProvider
 {
  LOGON32_PROVIDER_DEFAULT = 0,
  LOGON32_PROVIDER_WINNT35 = 1,
  LOGON32_PROVIDER_WINNT40 = 2,
  LOGON32_PROVIDER_WINNT50 = 3
 }

 #endregion

 public class ImpersonateService
 {

 // 사용해야하는 Windows API 의 선언 역시 내용 잘 모릅니다. ;;
  private WindowsImpersonationContext impersonationContext;

  // Win32 Security API
  [DllImport("advapi32.dll", SetLastError = true)]
  public 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)]
  public static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken);

  [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  public static extern bool RevertToSelf();

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

 

// 아~ 주석처리가 정말 아름답게 되어 있습니다. 지정한 사용자 계정으로 Impersonate 를 시작한답니다.

// 도메인은 서버가 도메인 구성이 되어 있을 경우에만 적절하게 넣으면 됩니다.

// 도메인 구성이 되어 있지 않을경우 공백... 뭐 아무거나 넣어도 잘 알아서 처리하더군요 ;; 역시 MS

  /// <summary>
  /// 지정한 사용자 계정으로 Impersonate를 시작한다.
  /// </summary>
  /// <param name="userName">계정명</param>
  /// <param name="domain">도메인</param>
  /// <param name="password">비밀번호</param>
  /// <returns>성공여부</returns>
  public bool impersonateVal‎idUser(string userName, string domain, string password)
  {
   WindowsIdentity tempWindowsIdentity;
   IntPtr token = IntPtr.Zero;
   IntPtr tokenDuplicate = IntPtr.Zero;

   if (RevertToSelf())
   {
    if (LogonUser(userName, domain, password, (int)LogonType.LOGON32_LOGON_INTERACTIVE, (int)LogonProvider.LOGON32_PROVIDER_DEFAULT, ref token) != 0)
    {
     if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
     {
      tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
      impersonationContext = tempWindowsIdentity.Impersonate();
      if (impersonationContext != null)
      {
       CloseHandle(token);
       CloseHandle(tokenDuplicate);
       return true;
      }
     }
    }
   }

   if (token != IntPtr.Zero) CloseHandle(token);
   if (tokenDuplicate != IntPtr.Zero) CloseHandle(tokenDuplicate);
   return false;
  }

// 다시 원래 실행하던 계정으로 돌립니다.

// 실행 페이지 등에서 이 클래스를 using 문으로 감싸주고 언로드에 실행시키면 굿!!

// 전 그냥 public 으로 선언해 주고 명시적으로 이 함수 호출해 줬습니다.

  /// <summary>
  /// Impersonate를 revoke하여 종료한다.
  /// </summary>
  public void undoImpersonation()
  {
   impersonationContext.Undo();
  }
 }
}

다음검색
현재 게시글 추가 기능 열기

댓글

댓글 리스트
맨위로

카페 검색

카페 검색어 입력폼