예: BITS에서 SSPI 인증 인코딩 사용
SSPI(보안 지원 공급자 인터페이스) 인증 및 BITS(Background Intelligent Transfer Service) 메서드를 사용하여 사용자로부터 자격 증명을 얻고, 자격 증명을 인코딩하고, BITS 전송 작업에서 인코딩된 자격 증명을 설정할 수 있습니다. 자격 증명 구조를 BITS 전송 작업에 전달할 수 있는 문자열로 변환하려면 인코딩이 필요합니다.
SSPI 인증 및 방법에 대한 자세한 내용은 SSPI를 참조하세요.
다음 절차에서는 협상 보안 패키지를 사용하여 사용자의 자격 증명을 묻는 메시지를 표시합니다. 프로그램은 인증 ID 구조를 만들고 사용자의 사용자 이름, 도메인 및 암호를 나타내는 인코딩된 문자열로 구조를 채웁니다. 그런 다음, 프로그램에서 BITS 다운로드 작업을 만들고 인코딩된 사용자 이름 및 암호를 작업의 자격 증명으로 설정합니다. 프로그램은 더 이상 필요하지 않은 인증 ID 구조를 해제합니다.
이 예제에서는 예제: 공용 클래스에 정의된 헤더 및 구현을 사용합니다.
BITS 전송 작업에서 SSPI 인증 인코딩을 사용하려면
- CCoInitializer 함수를 호출하여 COM 매개 변수를 초기화합니다. CCoInitializer 함수에 대한 자세한 내용은 예제: 공용 클래스를 참조하세요.
- IBackgroundCopyManager, IBackgroundCopyJob, IBackgroundCopyJob2 인터페이스에 대한 포인터를 가져옵니다. 이 예제에서는 CComPtr 클래스 를 사용하여 COM 인터페이스 포인터를 관리합니다.
- SspiPromptForCredentials 함수에 대한 대화 상자의 모양을 사용자 지정하기 위한 정보가 포함된 CREDUI_INFO 구조를 만듭니다. 그런 다음, 사용자의 자격 증명을 묻는 메시지를 표시합니다. 자세한 내용은 SspiPromptForCredentials 함수를 참조하세요.
- 자격 증명 구조를 SspiEncodeAuthIdentityAsStrings 함수를 사용하여 BITS 전송 작업에 전달할 수 있는 문자열로 인코딩합니다.
- BG_AUTH_CREDENTIALS 구조를 준비합니다.
- CoInitializeSecurity를 호출하여 COM 프로세스 보안을 초기화합니다. BITS에는 적어도 IMPERSONATE 수준의 가장이 필요합니다. 올바른 가장 수준이 설정되지 않은 경우 E_ACCESSDENIED BITS가 실패합니다.
- CoCreateInstance 함수를 호출하여 BITS에 대한 초기 로케이터를 가져옵니다.
- IBackgroundCopyManager::CreateJob 메서드를 호출하여 BITS 전송 작업을 만듭니다.
- IBackgroundCopyJob2 인터페이스의 식별자를 가져와서 IBackgroundCopyJob::QueryInterface 메서드를 호출합니다.
- BG_AUTH_CREDENTIALS 구조체를 인코딩된 사용자 이름 및 암호 문자열로 채우고 인증 체계를 협상(BG_AUTH_SCHEME_NEGOTIATE)으로 설정합니다.
- IBackgroundCopyJob2 포인터를 사용하여 BITS를 요청합니다. 이 프로그램은 IBackgroundCopyJob2::SetCredentials 메서드를 사용하여 BITS 전송 작업에 대한 자격 증명을 설정합니다.
- 파일을 추가하거나, 속성을 수정하거나, BITS 전송 작업을 다시 시작합니다.
- BITS 전송 작업이 완료되면 IBackgroundCopyJob::Complete를 호출하여 큐에서 작업을 제거합니다.
- 마지막으로 SspiFreeAuthIdentity 함수를 호출하여 인증 ID 구조를 해제합니다.
다음 코드 예제에서는 BITS 전송 작업과 함께 SSPI 인증 인코딩을 사용하는 방법을 보여 줍니다.
#define SECURITY_WIN32
#define _SEC_WINNT_AUTH_TYPES
#include <windows.h>
#include <ntsecapi.h>
#include <bits.h>
#include <sspi.h>
#include <wincred.h>
#include <iostream>
#include <atlbase.h>
#include "CommonCode.h"
void PromptForCredentials(PWSTR pwTargetName)
{
HRESULT hr;
// If CoInitializeEx fails, the exception is unhandled and the program terminates
CCoInitializer coInitializer(COINIT_APARTMENTTHREADED);
CComPtr<IBackgroundCopyManager> pQueueMgr;
CComPtr<IBackgroundCopyJob> pJob;
CComPtr<IBackgroundCopyJob2> pJob2;
PSEC_WINNT_AUTH_IDENTITY_OPAQUE pAuthIdentityEx2 = NULL;
DWORD dwFlags = 0;
BOOL fSave = FALSE;
BOOL bReturn = TRUE;
CREDUI_INFO creduiInfo = { 0 };
creduiInfo.cbSize = sizeof(creduiInfo);
// Change the message text and caption to the actual text for your dialog.
creduiInfo.pszMessageText = pwTargetName;
creduiInfo.pszCaptionText = L"SSPIPFC title for the dialog box";
try {
// Prompt for credentials from user using Negotiate security package.
DWORD dwRet = SspiPromptForCredentials(
pwTargetName,
&creduiInfo,
0,
L"Negotiate",
NULL,
&pAuthIdentityEx2,
&fSave,
dwFlags
);
if (SEC_E_OK != dwRet)
{
// Prompt for credentials failed.
throw MyException(dwRet, L"SspiPromptForCredentials");
}
if (NULL != pAuthIdentityEx2)
{
GUID guidJob;
BG_AUTH_CREDENTIALS authCreds;
PCWSTR pwUserName = NULL;
PCWSTR pwDomainName = NULL;
PCWSTR pwPassword = NULL;
// Encode credential structure as strings that can
// be passed to a BITS job.
SECURITY_STATUS secStatus = SspiEncodeAuthIdentityAsStrings(
pAuthIdentityEx2,
&pwUserName,
&pwDomainName,
&pwPassword
);
if(SEC_E_OK != secStatus)
{
// Encode authentication identity as strings.
throw MyException(secStatus, L"SspiEncodeAuthIdentityAsStrings");
}
// Show the encoded user name and domain name.
wprintf(
L"User Name: %s\nDomain Name: %s",
pwUserName,
pwDomainName
);
//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.
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.
hr = pQueueMgr->CreateJob(
L"EncodeSample",
BG_JOB_TYPE_DOWNLOAD,
&guidJob,
&pJob
);
if(FAILED(hr))
{
// Failed to create a BITS job.
throw MyException(hr, L"CreateJob");
}
// Get IBackgroundCopyJob2 interface.
hr = pJob->QueryInterface(__uuidof(IBackgroundCopyJob2), (void**)&pJob2);
if (FAILED(hr))
{
// Failed to get a reference to the IBackgroundCopyJob2 interface.
throw MyException(hr, L"QueryInterface(IBackgroundCopyJob2)");
}
// Create a BITS authentication structure from the encoded strings.
authCreds.Target = BG_AUTH_TARGET_SERVER;
authCreds.Scheme = BG_AUTH_SCHEME_NEGOTIATE;
authCreds.Credentials.Basic.UserName = (LPWSTR)pwUserName;
authCreds.Credentials.Basic.Password = (LPWSTR)pwPassword;
// Set the credentials for the job.
hr = pJob2->SetCredentials(&authCreds);
if (FAILED(hr))
{
// Failed to set credentials.
throw MyException(hr, L"SetCredentials");
}
// Modify the job's property values.
// Add files to the job.
// Activate (resume) the job in the transfer queue.
// Remove the job from the transfer queue.
hr = pJob->Complete();
if (FAILED(hr))
{
// Failed to complete the job.
throw MyException(hr, L"Complete");
}
}
}
catch(std::bad_alloc &)
{
wprintf(L"Memory allocation failed");
if (pJob != NULL)
{
pJob->Cancel();
}
}
catch(MyException &ex)
{
wprintf(L"Error %x occurred during operation", ex.Error);
if (pJob != NULL)
{
pJob->Cancel();
}
}
// Free the auth identity structure.
if (NULL != pAuthIdentityEx2)
{
SspiFreeAuthIdentity(pAuthIdentityEx2);
pAuthIdentityEx2 = NULL;
}
return;
}
void _cdecl _tmain(int argc, LPWSTR* argv)
{
PromptForCredentials(L"Target");
}
관련 항목