다음을 통해 공유


예: BITS 전송 작업에 도우미 토큰 추가

추가 보안 토큰을 사용하여 BITS(Background Intelligent Transfer Service) 전송 작업을 구성할 수 있습니다. BITS 전송 작업은 인증 및 리소스에 액세스하기 위해 이 도우미 토큰을 사용합니다.

자세한 내용은 BITS 전송 작업에 대한도우미 토큰을 참조하세요.

다음 절차에서는 로컬 사용자의 컨텍스트에서 BITS 전송 작업을 만들고, 두 번째 사용자의 자격 증명을 가져오고, 이러한 자격 증명으로 도우미 토큰을 만든 다음, BITS 전송 작업에서 도우미 토큰을 설정합니다.

이 예제에서는 예제: common 클래스정의된 헤더 및 구현을 사용합니다.

BITS 전송 작업에 도우미 토큰을 추가하려면

  1. CCoInitializer 함수를 호출하여 COM 매개 변수를 초기화합니다. CCoInitializer 함수에 대한 자세한 내용은 예제: common 클래스참조하세요.

  2. IBackgroundCopyJob 인터페이스에 대한 포인터를 가져옵니다. 이 예제에서는 CComPtr 클래스 사용하여 COM 인터페이스 포인터를 관리합니다.

  3. CoInitializeSecurity호출하여 COM 프로세스 보안을 초기화합니다. BITS에는 적어도 IMPERSONATE 수준의 가장이 필요합니다. 올바른 가장 수준이 설정되지 않은 경우 E_ACCESSDENIED BITS가 실패합니다.

  4. IBackgroundCopyManager 인터페이스에 대한 포인터를 가져오고 CoCreateInstance 함수를 호출하여 BITS에 대한 초기 로케이터를 가져옵니다.

  5. IBackgroundCopyManager::CreateJob 메서드를 호출하여 BITS 전송 작업을 만듭니다.

  6. CNotifyInterface 콜백 인터페이스에 대한 포인터를 가져와서 IBackgroundCopyJob::SetNotifyInterface 메서드를 호출하여 작업 관련 이벤트에 대한 알림을 받습니다. CNotifyInterface에 대한 자세한 내용은 예제: 공용 클래스참조하세요.

  7. IBackgroundCopyJob::SetNotifyFlags 메서드를 호출하여 수신할 알림 유형을 설정합니다. 이 예제에서는 BG_NOTIFY_JOB_TRANSFERREDBG_NOTIFY_JOB_ERROR 플래그가 설정됩니다.

  8. 적절한 인터페이스 식별자를 사용하여 IBackgroundCopyJob::QueryInterface 메서드를 호출하여 IBitsTokenOptions 인터페이스에 대한 포인터를 가져옵니다.

  9. 도우미 토큰의 사용자 로그온을 시도합니다. 가장 핸들을 만들고 LogonUser 함수 호출하여 가장 핸들을 채웁다. 성공하면 ImpersonateLoggedOnUser 함수호출합니다. 실패하면 RevertToSelf 함수 호출하여 로그온한 사용자의 가장을 종료하고 오류가 throw되고 핸들이 닫힙니다.

  10. IBitsTokenOptions::SetHelperToken 메서드를 호출하여 로그온한 사용자의 토큰을 가장합니다. 이 메서드가 실패하면 예제에서는 RevertToSelf 함수 호출하여 로그온한 사용자의 가장을 종료하고 오류가 throw되고 핸들이 닫힙니다.

    메모

    Windows 10 버전 1607 이전의 지원되는 Windows 버전에서 작업 소유자는 IBitsTokenOptions::SetHelperToken 메서드를 호출하기 위한 관리 자격 증명이 있어야 합니다.

    Windows 10 버전 1607부터 관리자가 아닌 작업 소유자는 소유한 BITS 작업에 관리자가 아닌 도우미 토큰을 설정할 수 있습니다. 관리자 권한으로 도우미 토큰을 설정하려면 작업 소유자에게 관리 자격 증명이 있어야 합니다.

     

  11. IBitsTokenOptions::SetHelperTokenFlags 메서드를 호출하여 도우미 토큰의 보안 컨텍스트를 사용하여 액세스할 리소스를 지정합니다.

  12. 가장이 완료되면 예제에서는 RevertToSelf 함수 호출하여 로그온한 사용자의 가장을 종료하고 핸들이 닫힙니다.

  13. IBackgroundCopyJob::AddFile호출하여 BITS 전송 작업에 파일을 추가합니다.

  14. 파일이 추가되면 IBackgroundCopyJob::Resume 호출하여 작업을 다시 시작합니다.

  15. 작업이 전송되는 동안 콜백 인터페이스에서 종료 메시지를 기다리도록 while 루프를 설정합니다. while 루프는 GetTickCount 함수를 사용하여 작업 전송을 시작한 이후 경과된 시간(밀리초)을 검색합니다.

  16. BITS 전송 작업이 완료되면 IBackgroundCopyJob::Complete호출하여 큐에서 작업을 제거합니다.

다음 코드 예제에서는 BITS 전송 작업에 도우미 토큰을 추가합니다.

#include <bits.h>
#include <bits4_0.h>
#include <stdio.h>
#include <tchar.h>
#include <lm.h>
#include <iostream>
#include <exception>
#include <string>
#include <atlbase.h>
#include <memory>
#include <new>
#include "CommonCode.h"


void HelperToken(const LPWSTR &remoteFile, const LPWSTR &localFile, const LPWSTR &domain, const LPWSTR &username, const LPWSTR &password)
{
// If CoInitializeEx fails, the exception is unhandled and the program terminates   
CCoInitializer coInitializer(COINIT_APARTMENTTHREADED);

CComPtr<IBackgroundCopyJob> pJob; 

    try
    {
        //The impersonation level must be at least RPC_C_IMP_LEVEL_IMPERSONATE.
        HRESULT hr = CoInitializeSecurity(
            NULL,
            -1,
            NULL,
            NULL,
            RPC_C_AUTHN_LEVEL_CONNECT,
            RPC_C_IMP_LEVEL_IMPERSONATE,
            NULL,
            EOAC_DYNAMIC_CLOAKING,
            0
            );

        if (FAILED(hr))
        {
            throw MyException(hr, L"CoInitializeSecurity");
        }

        // Connect to BITS.
        CComPtr<IBackgroundCopyManager> pQueueMgr;
        hr = CoCreateInstance(__uuidof(BackgroundCopyManager), NULL,
            CLSCTX_LOCAL_SERVER,
            __uuidof(IBackgroundCopyManager),
            (void **)&pQueueMgr);

        if (FAILED(hr))
        {
            // Failed to connect.
            throw MyException(hr, L"CoCreateInstance");
        }

        // Create a job.
        wprintf(L"Creating Job...\n");

        GUID guidJob;
        hr = pQueueMgr->CreateJob(L"HelperTokenSample",
            BG_JOB_TYPE_DOWNLOAD,
            &guidJob,
            &pJob);


        if(FAILED(hr))
        {   
            // Failed to create job.
            throw MyException(hr, L"CreateJob");
        }

        // Set the File Completed call.
        CComPtr<CNotifyInterface> pNotify;    
        pNotify = new CNotifyInterface();
        hr = pJob->SetNotifyInterface(pNotify);
        if (FAILED(hr))
        {
            // Failed to SetNotifyInterface.
            throw MyException(hr, L"SetNotifyInterface");
        }
        hr = pJob->SetNotifyFlags(BG_NOTIFY_JOB_TRANSFERRED | 
            BG_NOTIFY_JOB_ERROR);

        if (FAILED(hr))
        {
            // Failed to SetNotifyFlags.
            throw MyException(hr, L"SetNotifyFlags");
        }

        //Retrieve the IBitsTokenOptions interface pointer from the BITS transfer job.
        CComPtr<IBitsTokenOptions> pTokenOptions;
        hr = pJob->QueryInterface(__uuidof(IBitsTokenOptions), (void** ) &pTokenOptions);

        if (FAILED(hr))
        {
            // Failed to QueryInterface.
            throw MyException(hr, L"QueryInterface");
        }

        // Log on user of the helper token.
        wprintf(L"Credentials for helper token %s\\%s %s\n", domain, username, password);

        HANDLE hImpersonation = INVALID_HANDLE_VALUE;
        if(LogonUser(username, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hImpersonation))
        {
            // Impersonate the logged-on user.
            if(ImpersonateLoggedOnUser(hImpersonation))
            {
                // Configure the impersonated logged-on user's token as the helper token.
                hr = pTokenOptions->SetHelperToken();        
                if (FAILED(hr))
                {
                    //Failed to set helper token.
                    CloseHandle(hImpersonation);
                    RevertToSelf();
                    throw MyException(hr, L"SetHelperToken");
                }

                hr = pTokenOptions->SetHelperTokenFlags(BG_TOKEN_LOCAL_FILE);
                if (FAILED(hr))
                {
                    //Failed to set helper token flags.
                    CloseHandle(hImpersonation);
                    RevertToSelf();
                    throw MyException(hr, L"SetHelperTokenFlags");
                }

                RevertToSelf();
            }               
            CloseHandle(hImpersonation);
        }

        // Add a file.
        // Replace parameters with variables that contain valid paths.
        wprintf(L"Adding File to Job\n");
        hr = pJob->AddFile(remoteFile,localFile);

        if(FAILED(hr))
        {   
            //Failed to add file to job.
            throw MyException(hr, L"AddFile");
        }

        //Resume the job.
        wprintf(L"Resuming Job...\n");
        hr = pJob->Resume();
        if (FAILED(hr))
        {
            // Resume failed.                   
            throw MyException(hr, L"Resume");
        }    
    }
    catch(const std::bad_alloc &)
    {
        wprintf(L"Memory allocation failed");
        if (pJob)
        {
            pJob->Cancel();
        }

        return;
    }
    catch(const MyException &ex)
    {
        wprintf(L"Error 0x%x occurred during operation", ex.Error);
        if (pJob)
        {
            pJob->Cancel();
        }

        return;
    }

    wprintf(L"Transferring file and waiting for callback.\n");

    // Wait for QuitMessage from CallBack
    DWORD dwLimit = GetTickCount() + (15 * 60 * 1000);  // set 15 minute limit
    while (dwLimit > GetTickCount())
    {
        MSG msg;

        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
        { 
            // If it is a quit message, exit.
            if (msg.message == WM_QUIT) 
            {
                return;
            }

            // Otherwise, dispatch the message.
            DispatchMessage(&msg); 
        } // End of PeekMessage while loop
    }

    pJob->Cancel();
    return;
}

void _cdecl _tmain(int argc, LPWSTR* argv)
{   
    if (argc != 6)
    {
        wprintf(L"Usage:");
        wprintf(L"%s ", argv[0]);
        wprintf(L"[remote name] [local name] [helpertoken domain] [helpertoken userrname] [helpertoken password]\n");
        return;
    }

    HelperToken(argv[1],argv[2],argv[3],argv[4],argv[5]);

}

BITS 전송 작업에 대한 도우미 토큰

IBitsTokenOptions

예제: 공용 클래스