Especificar credenciais de autenticação do servidor para um trabalho de transferência do BITS
Você pode especificar esquemas de autenticação diferentes para um trabalho de transferência do BITS (Serviço de Transferência Inteligente em Segundo Plano).
O procedimento a seguir obtém um esquema de autenticação e cria uma estrutura de identidade de autenticação. Em seguida, o aplicativo cria um trabalho de download do BITS e define as credenciais para o trabalho. Depois que o trabalho é criado, o aplicativo obtém um ponteiro para uma interface de retorno de chamada e pesquisa o status do trabalho de transferência do BITS. Depois que o trabalho for concluído, ele será removido da fila.
Este exemplo usa o cabeçalho e a implementação definidos em Example: Common Classes.
Para especificar credenciais de autenticação de servidor para um trabalho de transferência do BITS
Crie uma estrutura de contêiner que mapeie valores BG_AUTH_SCHEME para nomes de esquema.
struct { LPCWSTR Name; BG_AUTH_SCHEME Scheme; } SchemeNames[] = { { L"basic", BG_AUTH_SCHEME_BASIC }, { L"digest", BG_AUTH_SCHEME_DIGEST }, { L"ntlm", BG_AUTH_SCHEME_NTLM }, { L"negotiate", BG_AUTH_SCHEME_NEGOTIATE }, { L"passport", BG_AUTH_SCHEME_PASSPORT }, { NULL, BG_AUTH_SCHEME_BASIC } };
Inicialize os parâmetros COM chamando a função CCoInitializer. Para obter mais informações sobre a função CCoInitializer, consulte Exemplo: classes comuns.
Prepare uma estrutura BG_AUTH_CREDENTIALS. O exemplo usa a função SecureZeroMemory para limpar os locais de memória associados às informações confidenciais. A função SecureZeroMemory é definida em WinBase.h.
Use a função GetScheme para obter o esquema de autenticação a ser usado para se conectar ao servidor.
bool GetScheme( LPCWSTR s, BG_AUTH_SCHEME *scheme ) { int i; i = 0; while (SchemeNames[i].Name != NULL) { if (0 == _wcsicmp( s, SchemeNames[i].Name )) { *scheme = SchemeNames[i].Scheme; return true; } ++i; } return false; }
Preencha a estrutura BG_AUTH_CREDENTIALS com o esquema de autenticação retornado pela função GetScheme e o nome de usuário e a senha que foram passados para a função ServerAuthentication.
Obtenha um ponteiro para a interface IBackgroundCopyJob (pJob).
Inicialize a segurança do processo COM chamando CoInitializeSecurity. O BITS requer pelo menos o nível IMPERSONATE de representação. O BITS falhará com E_ACCESSDENIED se o nível de representação correto não estiver definido.
Obtenha um ponteiro para a interface IBackgroundCopyManager e obtenha o localizador inicial para o BITS chamando a função CoCreateInstance.
Crie um trabalho de transferência do BITS chamando o método IBackgroundCopyManager::CreateJob .
Obtenha um ponteiro para a interface de retorno de chamada CNotifyInterface e chame o método IBackgroundCopyJob::SetNotifyInterface para receber notificação de eventos relacionados ao trabalho. Para obter mais informações sobre CNotifyInterface, consulte Exemplo: classes comuns.
Chame o método IBackgroundCopyJob::SetNotifyFlags para definir os tipos de notificações a serem recebidas. Neste exemplo, os sinalizadores BG_NOTIFY_JOB_TRANSFERRED e BG_NOTIFY_JOB_ERROR são definidos.
Obtenha um ponteiro para a interface IBackgroundCopyJob2. Use o ponteiro IBackgroundCopyJob2 para definir propriedades adicionais no trabalho. Este programa usa o método IBackgroundCopyJob2::SetCredentials para definir as credenciais para o trabalho de transferência do BITS.
Adicione arquivos ao trabalho de transferência do BITS chamando IBackgroundCopyJob::AddFile. Neste exemplo, o método IBackgroundCopyJob::AddFile usa as variáveis remoteFile e localFile que foram passadas para a função ServerAuthentication.
Depois que o arquivo for adicionado, chame IBackgroundCopyJob::Resume para retomar o trabalho.
Configure um loop while para aguardar Quit Message da interface de retorno de chamada enquanto o trabalho está sendo transferido.
Observação
Esta etapa é necessária apenas se o apartamento COM for um apartamento de thread único. Para obter mais informações, consulte Single-Threaded Apartments.
// 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 }
O loop anterior usa a função GetTickCount para recuperar o número de milissegundos decorridos desde que o trabalho começou a ser transferido.
Depois que o trabalho de transferência do BITS for concluído, remova o trabalho da fila chamando IBackgroundCopyJob::Complete.
O exemplo de código a seguir especifica as credenciais de autenticação do servidor para um trabalho de transferência do 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"
//
// Retrieve BG_AUTH_SCHEME from scheme name.
//
//
struct
{
LPCWSTR Name;
BG_AUTH_SCHEME Scheme;
}
SchemeNames[] =
{
{ L"basic", BG_AUTH_SCHEME_BASIC },
{ L"digest", BG_AUTH_SCHEME_DIGEST },
{ L"ntlm", BG_AUTH_SCHEME_NTLM },
{ L"negotiate", BG_AUTH_SCHEME_NEGOTIATE },
{ L"passport", BG_AUTH_SCHEME_PASSPORT },
{ NULL, BG_AUTH_SCHEME_BASIC }
};
bool GetScheme( LPCWSTR s, BG_AUTH_SCHEME *scheme )
{
int i;
i = 0;
while (SchemeNames[i].Name != NULL)
{
if (0 == _wcsicmp( s, SchemeNames[i].Name ))
{
*scheme = SchemeNames[i].Scheme;
return true;
}
++i;
}
return false;
}
void ServerAuthentication(const LPWSTR &remoteFile, const LPWSTR &localFile, const LPWSTR &scheme, const LPWSTR &username, const LPWSTR &password)
{
// If CoInitializeEx fails, the exception is unhandled and the program terminates
CCoInitializer coInitializer(COINIT_APARTMENTTHREADED);
// Prepare the credentials structure.
BG_AUTH_CREDENTIALS cred;
ZeroMemory(&cred, sizeof(cred));
if (!GetScheme(scheme,&cred.Scheme))
{
wprintf(L"Invalid authentication scheme specified\n");
return;
}
cred.Target = BG_AUTH_TARGET_SERVER;
cred.Credentials.Basic.UserName = username;
if (0 == _wcsicmp(cred.Credentials.Basic.UserName, L"NULL"))
{
cred.Credentials.Basic.UserName = NULL;
}
cred.Credentials.Basic.Password = password;
if (0 == _wcsicmp(cred.Credentials.Basic.Password, L"NULL"))
{
cred.Credentials.Basic.Password = NULL;
}
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"BitsAuthSample",
BG_JOB_TYPE_DOWNLOAD,
&guidJob,
&pJob);
if (FAILED(hr))
{
// Failed to connect.
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 connect.
throw MyException(hr, L"SetNotifyInterface");
}
hr = pJob->SetNotifyFlags(BG_NOTIFY_JOB_TRANSFERRED |
BG_NOTIFY_JOB_ERROR);
if (FAILED(hr))
{
// Failed to connect.
throw MyException(hr, L"SetNotifyFlags");
}
// Set credentials.
CComPtr<IBackgroundCopyJob2> job2;
hr = pJob.QueryInterface(&job2);
if (FAILED(hr))
{
// Failed to connect.
throw MyException(hr, L"QueryInterface");
}
hr = job2->SetCredentials(&cred);
if (FAILED(hr))
{
// Failed to connect.
throw MyException(hr, L"SetCredentials");
}
// Add a file.
wprintf(L"Adding File to Job\n");
hr = pJob->AddFile(remoteFile, localFile);
if (FAILED(hr))
{
// Failed to connect.
throw MyException(hr, L"AddFile");
}
//Resume the job.
wprintf(L"Resuming Job...\n");
hr = pJob->Resume();
if (FAILED(hr))
{
// Failed to connect.
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 %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] [server authentication scheme =\"NTLM\"|\"NEGOTIATE\"|\"BASIC\"|\"DIGEST\"] [username] [password]\n");
return;
}
ServerAuthentication(argv[1], argv[2], argv[3], argv[4], argv[5]);
}
Tópicos relacionados