Partager via


Spécifier les informations d’identification d’authentification du serveur pour un travail de transfert BITS

Vous pouvez spécifier différents schémas d’authentification pour un travail de transfert BITS (Background Intelligent Transfer Service).

La procédure suivante obtient un schéma d’authentification et crée une structure d’identité d’authentification. Ensuite, l’application crée un travail de téléchargement BITS et définit les informations d’identification pour le travail. Une fois le travail créé, l’application obtient un pointeur vers une interface de rappel et interroge la status du travail de transfert BITS. Une fois le travail terminé, il est supprimé de la file d’attente.

Cet exemple utilise l’en-tête et l’implémentation définis dans Exemple : Classes courantes.

Pour spécifier les informations d’identification d’authentification du serveur pour un travail de transfert BITS

  1. Créez une structure de conteneur qui mappe BG_AUTH_SCHEME valeurs aux noms de schémas.

    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 }
    };
    
  2. Initialisez les paramètres COM en appelant la fonction CCoInitializer. Pour plus d’informations sur la fonction CCoInitializer, consultez Exemple : Classes courantes.

  3. Préparer une structure BG_AUTH_CREDENTIALS . L’exemple utilise la fonction SecureZeroMemory pour effacer les emplacements de mémoire associés aux informations sensibles. La fonction SecureZeroMemory est définie dans WinBase.h.

  4. Utilisez la fonction GetScheme pour obtenir le schéma d’authentification à utiliser pour se connecter au serveur.

    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;
    }
    
  5. Renseignez la structure BG_AUTH_CREDENTIALS avec le schéma d’authentification retourné par la fonction GetScheme, ainsi que le nom d’utilisateur et le mot de passe qui ont été passés à la fonction ServerAuthentication.

  6. Obtenez un pointeur vers l’interface IBackgroundCopyJob (pJob).

  7. Initialisez la sécurité des processus COM en appelant CoInitializeSecurity. BITS nécessite au moins le niveau IMPERSONATE d’emprunt d’identité. BITS échoue avec E_ACCESSDENIED si le niveau d’emprunt d’identité correct n’est pas défini.

  8. Obtenez un pointeur vers l’interface IBackgroundCopyManager et obtenez le localisateur initial vers BITS en appelant la fonction CoCreateInstance .

  9. Créez un travail de transfert BITS en appelant la méthode IBackgroundCopyManager::CreateJob .

  10. Obtenez un pointeur vers l’interface de rappel CNotifyInterface et appelez la méthode IBackgroundCopyJob::SetNotifyInterface pour recevoir une notification des événements liés au travail. Pour plus d’informations sur CNotifyInterface, consultez Exemple : Classes courantes.

  11. Appelez la méthode IBackgroundCopyJob::SetNotifyFlags pour définir les types de notifications à recevoir. Dans cet exemple, les indicateurs BG_NOTIFY_JOB_TRANSFERRED et BG_NOTIFY_JOB_ERROR sont définis.

  12. Obtenez un pointeur vers l’interface IBackgroundCopyJob2 . Utilisez le pointeur IBackgroundCopyJob2 pour définir des propriétés supplémentaires sur le travail. Ce programme utilise la méthode IBackgroundCopyJob2::SetCredentials pour définir les informations d’identification du travail de transfert BITS.

  13. Ajoutez des fichiers au travail de transfert BITS en appelant IBackgroundCopyJob::AddFile. Dans cet exemple, la méthode IBackgroundCopyJob::AddFile utilise les variables remoteFile et localFile qui ont été passées à la fonction ServerAuthentication.

  14. Une fois le fichier ajouté, appelez IBackgroundCopyJob::Resume pour reprendre le travail.

  15. Configurez une boucle de temps pour attendre quitter le message à partir de l’interface de rappel pendant le transfert du travail.

    Notes

    Cette étape n’est nécessaire que si l’appartement COM est un appartement monothread. Pour plus d’informations, consultez Appartements à thread unique.

     

    // 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
        }
    

    La boucle précédente utilise la fonction GetTickCount pour récupérer le nombre de millisecondes écoulées depuis le début du transfert du travail.

  16. Une fois le travail de transfert BITS terminé, supprimez le travail de la file d’attente en appelant IBackgroundCopyJob::Complete.

L’exemple de code suivant spécifie les informations d’identification d’authentification du serveur pour un travail de transfert 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]); 

}

IBackgroundCopyManager

IBackgroundCopyJob

IBackgroundCopyJob2

Exemple : Classes courantes