Specificare le credenziali di autenticazione del server per un processo di trasferimento BITS
È possibile specificare diversi schemi di autenticazione per un processo di trasferimento BITS (Background Intelligent Transfer Service).
La procedura seguente ottiene uno schema di autenticazione e crea una struttura di identità di autenticazione. L'applicazione crea quindi un processo di download BITS e imposta le credenziali per il processo. Dopo aver creato il processo, l'applicazione ottiene un puntatore a un'interfaccia di callback ed esegue il polling dello stato del processo di trasferimento BITS. Al termine del processo, il processo viene rimosso dalla coda.
In questo esempio viene usata l'intestazione e l'implementazione definita in Esempio: Classi comuni.
Per specificare le credenziali di autenticazione server per un processo di trasferimento BITS
Creare una struttura del contenitore che esegue il mapping dei valori BG_AUTH_SCHEME ai nomi degli schemi.
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 } };
Inizializzare i parametri COM chiamando la funzione CCoInitializer. Per altre informazioni sulla funzione CCoInitializer, vedere Esempio: Classi comuni.
Preparare una struttura BG_AUTH_CREDENTIALS. Nell'esempio viene utilizzata la funzione SecureZeroMemory per cancellare i percorsi di memoria associati alle informazioni riservate. La funzione SecureZeroMemory è definita in WinBase.h.
Usare la funzione GetScheme per ottenere lo schema di autenticazione da usare per connettersi al server.
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; }
Popolare la struttura BG_AUTH_CREDENTIALS con lo schema di autenticazione restituito dalla funzione GetScheme e dal nome utente e dalla password passati alla funzione ServerAuthentication.
Ottenere un puntatore all'interfaccia IBackgroundCopyJob (pJob ).
Inizializzare la sicurezza del processo COM chiamando CoInitializeSecurity. BITS richiede almeno il livello IMPERSONATE di rappresentazione. BITS ha esito negativo con E_ACCESSDENIED se il livello di rappresentazione corretto non è impostato.
Ottenere un puntatore all'interfaccia IBackgroundCopyManager e ottenere il localizzatore iniziale in BITS chiamando la funzione CoCreateInstance.
Creare un processo di trasferimento BITS chiamando il metodo IBackgroundCopyManager::CreateJob.
Ottenere un puntatore all'interfaccia di callback CNotifyInterface e chiamare il metodo IBackgroundCopyJob::SetNotifyInterface per ricevere la notifica degli eventi correlati al processo. Per altre informazioni su CNotifyInterface, vedere Esempio: Classi comuni.
Chiamare il metodo IBackgroundCopyJob::SetNotifyFlags per impostare i tipi di notifiche da ricevere. In questo esempio vengono impostati i flag BG_NOTIFY_JOB_TRANSFERRED e BG_NOTIFY_JOB_ERROR .
Ottenere un puntatore all'interfaccia IBackgroundCopyJob2 . Usare il puntatore IBackgroundCopyJob2 per impostare proprietà aggiuntive nel processo. Questo programma usa il metodo IBackgroundCopyJob2::SetCredentials per impostare le credenziali per il processo di trasferimento BITS.
Aggiungere file al processo di trasferimento BITS chiamando IBackgroundCopyJob::AddFile. In questo esempio il metodo IBackgroundCopyJob::AddFile usa le variabili remoteFile e localFile passate alla funzione ServerAuthentication.
Dopo aver aggiunto il file, chiama IBackgroundCopyJob::Resume per riprendere il processo.
Configurare un ciclo while per attendere la chiusura del messaggio dall'interfaccia di callback durante il trasferimento del processo.
Nota
Questo passaggio è necessario solo se l'apartment COM è un apartment a thread singolo. Per altre informazioni, vedere Appartamenti a thread singolo.
// 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 }
Il ciclo precedente usa la funzione GetTickCount per recuperare il numero di millisecondi trascorsi dall'avvio del trasferimento del processo.
Al termine del processo di trasferimento BITS, rimuovere il processo dalla coda chiamando IBackgroundCopyJob::Complete.
Nell'esempio di codice seguente vengono specificate le credenziali di autenticazione server per un processo di trasferimento 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]);
}
Argomenti correlati