Bagikan melalui


Contoh: Menggunakan Pengodean Autentikasi SSPI dengan BITS

Anda dapat menggunakan metode Autentikasi Antarmuka Penyedia Dukungan Keamanan (SSPI) dan Layanan Transfer Cerdas Latar Belakang (BITS) untuk mendapatkan kredensial dari pengguna, mengodekan kredensial, dan mengatur kredensial yang dikodekan pada pekerjaan transfer BITS. Pengodean diperlukan untuk mengonversi struktur info masuk menjadi string yang dapat diteruskan ke pekerjaan transfer BITS.

Untuk informasi selengkapnya tentang autentikasi dan metode SSPI, lihat SSPI.

Prosedur berikut meminta kredensial dari pengguna dengan menggunakan paket Negosiasi keamanan. Program ini membuat struktur identitas autentikasi dan mengisi struktur dengan string yang dikodekan yang mewakili nama pengguna, domain, dan kata sandi pengguna. Kemudian program membuat pekerjaan pengunduhan BITS dan mengatur nama pengguna dan kata sandi yang dikodekan sebagai kredensial untuk pekerjaan tersebut. Program membebaskan struktur identitas autentikasi setelah tidak lagi diperlukan.

Contoh ini menggunakan header dan implementasi yang ditentukan dalam Contoh: Kelas Umum.

Untuk menggunakan pengodean autentikasi SSPI dengan pekerjaan transfer BITS

  1. Inisialisasi parameter COM dengan memanggil fungsi CCoInitializer. Untuk informasi selengkapnya tentang fungsi CCoInitializer, lihat Contoh: Kelas Umum.
  2. Dapatkan pointer untuk antarmuka IBackgroundCopyManager, IBackgroundCopyJob, IBackgroundCopyJob2. Contoh ini menggunakan Kelas CComPtr untuk mengelola pointer antarmuka COM.
  3. Buat struktur CREDUI_INFO yang berisi informasi untuk menyesuaikan tampilan kotak dialog untuk Fungsi SspiPromptForCredentials. Kemudian minta kredensial dari pengguna. Untuk informasi selengkapnya, lihat Fungsi SspiPromptForCredentials.
  4. Mengodekan struktur kredensial sebagai string yang dapat diteruskan ke pekerjaan transfer BITS dengan menggunakan fungsi SspiEncodeAuthIdentityAsStrings .
  5. Siapkan struktur BG_AUTH_CREDENTIALS .
  6. Menginisialisasi keamanan proses COM dengan memanggil CoInitializeSecurity. BITS memerlukan setidaknya tingkat impersonasi IMPERSONATE. BITS gagal dengan E_ACCESSDENIED jika tingkat peniruan yang benar tidak diatur.
  7. Dapatkan pencari lokasi awal ke BITS dengan memanggil fungsi CoCreateInstance .
  8. Buat pekerjaan transfer BITS dengan memanggil metode IBackgroundCopyManager::CreateJob.
  9. Dapatkan pengidentifikasi untuk antarmuka IBackgroundCopyJob2 , dan panggil metode IBackgroundCopyJob::QueryInterface .
  10. Isi struktur BG_AUTH_CREDENTIALS dengan nama pengguna dan string kata sandi yang dikodekan, dan atur skema autentikasi ke Negosiasi (BG_AUTH_SCHEME_NEGOTIATE).
  11. Gunakan pointer IBackgroundCopyJob2 untuk membuat permintaan ke BITS. Program ini menggunakan metode IBackgroundCopyJob2::SetCredentials untuk mengatur kredensial untuk pekerjaan transfer BITS.
  12. Tambahkan file, ubah properti, atau lanjutkan pekerjaan transfer BITS.
  13. Setelah pekerjaan transfer BITS selesai, hapus pekerjaan dari antrean dengan memanggil IBackgroundCopyJob::Complete.
  14. Terakhir, bebaskan struktur identitas autentikasi dengan memanggil fungsi SspiFreeAuthIdentity .

Contoh kode berikut menunjukkan cara menggunakan Pengodean Autentikasi SSPI dengan pekerjaan transfer BITS.

#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");
}

SSPI

IBackgroundCopyManager

IBackgroundCopyJob

IBackgroundCopyJob2

Contoh: Kelas Umum