Gestion de l’authentification

Certains serveurs et proxys nécessitent une authentification avant d’accorder l’accès aux ressources sur Internet. Les fonctions WinINet prennent en charge l’authentification du serveur et du proxy pour les sessions HTTP. L’authentification des serveurs FTP doit être gérée par la fonction InternetConnect . Actuellement, l’authentification par passerelle FTP n’est pas prise en charge.

À propos de l’authentification HTTP

Si l’authentification est requise, l’application cliente reçoit un code status 401, si le serveur nécessite une authentification, ou 407, si le proxy nécessite une authentification. Avec le code status, le proxy ou le serveur envoie un ou plusieurs en-têtes de réponse d’authentification : Proxy-Authenticate (pour l’authentification proxy) ou WWW-Authenticate (pour l’authentification serveur).

Chaque en-tête de réponse d’authentification contient un schéma d’authentification disponible et un domaine. Si plusieurs schémas d’authentification sont pris en charge, le serveur retourne plusieurs en-têtes de réponse d’authentification. La valeur du domaine respecte la casse et définit un espace de protection sur le proxy ou le serveur. Par exemple, l’en-tête « WWW-Authenticate: Basic Realm= » example » est un exemple d’en-tête retourné lorsque l’authentification du serveur est requise.

L’application cliente qui a envoyé la demande peut s’authentifier en incluant un champ d’en-tête d’autorisation avec la demande. L’en-tête Authorization contient le schéma d’authentification et la réponse appropriée requise par ce schéma. Par exemple, l’en-tête « Authorization: Basic <username:password> » est ajouté à la demande et renvoyé au serveur si le client a reçu l’en-tête de réponse d’authentification « WWW-Authenticate: Basic Realm=»example » .

Il existe deux types généraux de schémas d’authentification :

  • Schéma d’authentification de base, où le nom d’utilisateur et le mot de passe sont envoyés en texte clair au serveur.
  • Les schémas de défi-réponse, qui permettent d’utiliser un format défi-réponse.

Le schéma d’authentification de base est basé sur le modèle qu’un client doit s’authentifier avec un nom d’utilisateur et un mot de passe pour chaque domaine. Le serveur traite la demande si elle est envoyée avec un en-tête d’autorisation qui inclut un nom d’utilisateur et un mot de passe valides.

Les schémas de défi-réponse permettent une authentification plus sécurisée. Si une demande nécessite une authentification à l’aide d’un schéma de demande-réponse, le code de status et les en-têtes d’authentification appropriés sont retournés au client. Le client doit ensuite renvoyer la demande avec une négociation. Le serveur retourne un code de status approprié avec un défi, et le client doit alors renvoyer la demande avec la réponse appropriée pour obtenir le service demandé.

Le tableau suivant répertorie les schémas d’authentification, le type d’authentification, la DLL qui les prend en charge et une description du schéma.

Schéma Type DLL Description
De base (texte en clair) basic Wininet.dll Utilise une chaîne encodée en base64 qui contient le nom d’utilisateur et le mot de passe.
Digest défi-réponse Digest.dll Schéma défi-réponse qui défie l’utilisation d’une valeur nonce (chaîne de données spécifiée par le serveur). Une réponse valide contient une somme de contrôle du nom d’utilisateur, du mot de passe, de la valeur de nonce donnée, de la méthode HTTP et de l’URI (Uniform Resource Identifier) demandé. La prise en charge de l’authentification Digest a été introduite dans Microsoft Internet Explorer 5.
NT LAN Manager (NTLM) défi-réponse Winsspi.dll Schéma de défi-réponse qui base le défi sur le nom d’utilisateur.
Microsoft Network (MSN) défi-réponse Msnsspc.dll Schéma d’authentification de Microsoft Network.
Authentification par mot de passe distribuée (DPA) défi-réponse Msapsspc.dll Similaire à l’authentification MSN et est également utilisé par microsoft Network.
Authentification de phrase secrète à distance (RPA) Compuserve Rpawinet.dll, da.dll Schéma d’authentification CompuServe. Pour plus d’informations, consultez spécifications du mécanisme RPA.

 

Pour toute autre chose que l’authentification de base, les clés de Registre doivent être configurées en plus de l’installation de la DLL appropriée.

Si l’authentification est requise, l’indicateur INTERNET_FLAG_KEEP_CONNECTION doit être utilisé dans l’appel à HttpOpenRequest. L’indicateur INTERNET_FLAG_KEEP_CONNECTION est requis pour NTLM et d’autres types d’authentification afin de maintenir la connexion tout en effectuant le processus d’authentification. Si la connexion n’est pas maintenue, le processus d’authentification doit être redémarré avec le proxy ou le serveur.

Les fonctions InternetOpenUrl et HttpSendRequest se terminent correctement même lorsque l’authentification est requise. La différence est que les données retournées dans les fichiers d’en-tête et InternetReadFile reçoivent une page HTML informant l’utilisateur du code status.

Inscription des clés d’authentification

INTERNET_OPEN_TYPE_PRECONFIG examine les valeurs de Registre ProxyEnable, ProxyServer et ProxyOverride. Ces valeurs se trouvent sous HKEY_CURRENT_USER\Paramètres Internet\Microsoft\Windows\CurrentVersion\.

Pour les schémas d’authentification autres que de base, une clé doit être ajoutée au Registre sous HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Sécurité. Une valeur DWORD , Indicateurs, doit être définie avec la valeur appropriée. La liste suivante présente les valeurs possibles pour la valeur Flags .

  • PLUGIN_AUTH_FLAGS_UNIQUE_CONTEXT_PER_TCPIP (value=0x01)

    Chaque socket TCP/IP (Transmission Control Protocol/Internet Protocol) contient un contexte différent. Sinon, un nouveau contexte est passé pour chaque modèle d’URL de domaine ou de bloc.

  • PLUGIN_AUTH_FLAGS_CAN_HANDLE_UI (value=0x02)

    Cette DLL peut gérer sa propre entrée utilisateur.

  • PLUGIN_AUTH_FLAGS_CAN_HANDLE_NO_PASSWD (value=0x04)

    Cette DLL peut être capable d’effectuer une authentification sans demander à l’utilisateur de fournir un mot de passe.

  • PLUGIN_AUTH_FLAGS_NO_REALM (value=0x08)

    Cette DLL n’utilise pas de chaîne de domaine http standard. Toutes les données qui semblent être un domaine sont des données spécifiques au schéma.

  • PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED (value=0x10)

    Cette DLL ne nécessite pas de connexion persistante pour sa séquence de défi-réponse.

Par exemple, pour ajouter l’authentification NTLM, la clé NTLM doit être ajoutée à HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Security. Sous HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Security\NTLM, la valeur de chaîne, DLLFile et une valeur DWORD, Flags, doivent être ajoutées. DLLFile doit être défini sur Winsspi.dll, et Indicateurs doit être défini sur 0x08.

Authentification du serveur

Lorsqu’un serveur reçoit une demande qui nécessite une authentification, le serveur retourne un message de code 401 status. Dans ce message, le serveur doit inclure un ou plusieurs en-têtes de réponse WWW-Authenticate. Ces en-têtes incluent les méthodes d’authentification disponibles sur le serveur. WinINet choisit la première méthode qu’il reconnaît.

L’authentification de base offre une sécurité faible, sauf si le canal est d’abord chiffré par liaison avec SSL ou PCT.

La fonction InternetErrorDlg peut être utilisée pour obtenir le nom d’utilisateur et les données de mot de passe de l’utilisateur, ou une interface utilisateur personnalisée peut être conçue pour obtenir les données.

Une interface personnalisée peut utiliser la fonction InternetSetOption pour définir les valeurs INTERNET_OPTION_PASSWORD et INTERNET_OPTION_USERNAME , puis renvoyer la demande au serveur.

Authentification proxy

Lorsqu’un client tente d’utiliser un proxy qui nécessite une authentification, le proxy retourne un message de code 407 status au client. Dans ce message, le proxy doit inclure un ou plusieurs en-têtes de réponse Proxy-Authenticate. Ces en-têtes incluent les méthodes d’authentification disponibles à partir du proxy. WinINet choisit la première méthode qu’il reconnaît.

La fonction InternetErrorDlg peut être utilisée pour obtenir les données de nom d’utilisateur et de mot de passe de l’utilisateur, ou une interface utilisateur personnalisée peut être conçue.

Une interface personnalisée peut utiliser la fonction InternetSetOption pour définir les valeurs INTERNET_OPTION_PROXY_PASSWORD et INTERNET_OPTION_PROXY_USERNAME , puis renvoyer la demande au proxy.

Si aucun nom d’utilisateur et mot de passe de proxy n’est défini, WinINet tente d’utiliser le nom d’utilisateur et le mot de passe du serveur. Ce comportement permet aux clients d’implémenter la même interface utilisateur personnalisée que celle utilisée pour gérer l’authentification du serveur.

Gestion de l’authentification HTTP

L’authentification HTTP peut être gérée avec InternetErrorDlg ou une fonction personnalisée qui utilise InternetSetOption ou ajoute ses propres en-têtes d’authentification. InternetErrorDlg peut examiner les en-têtes associés à un handle HINTERNET pour rechercher des erreurs masquées, telles que des codes status à partir d’un proxy ou d’un serveur. InternetSetOption peut être utilisé pour définir le nom d’utilisateur et le mot de passe du proxy et du serveur. Pour l’authentification MSN et DPA, InternetErrorDlg doit être utilisé pour définir le nom d’utilisateur et le mot de passe.

Pour toute fonction personnalisée qui ajoute ses propres WWW-Authenticate ou Proxy-Authenticate en-têtes, l’indicateur INTERNET_FLAG_NO_AUTH doit être défini pour désactiver l’authentification.

L’exemple suivant montre comment InternetErrorDlg peut être utilisé pour gérer l’authentification HTTP.

HINTERNET hOpenHandle,  hConnectHandle, hResourceHandle;
DWORD dwError, dwErrorCode;
HWND hwnd = GetConsoleWindow();

hOpenHandle = InternetOpen(TEXT("Example"),
                           INTERNET_OPEN_TYPE_PRECONFIG, 
                           NULL, NULL, 0);

hConnectHandle = InternetConnect(hOpenHandle,
                                 TEXT("www.server.com"), 
                                 INTERNET_INVALID_PORT_NUMBER,
                                 NULL,
                                 NULL, 
                                 INTERNET_SERVICE_HTTP,
                                 0,0);

hResourceHandle = HttpOpenRequest(hConnectHandle, TEXT("GET"),
                                  TEXT("/premium/default.htm"),
                                  NULL, NULL, NULL, 
                                  INTERNET_FLAG_KEEP_CONNECTION, 0);

resend:

HttpSendRequest(hResourceHandle, NULL, 0, NULL, 0);

// dwErrorCode stores the error code associated with the call to
// HttpSendRequest.  

dwErrorCode = hResourceHandle ? ERROR_SUCCESS : GetLastError();

dwError = InternetErrorDlg(hwnd, hResourceHandle, dwErrorCode, 
                           FLAGS_ERROR_UI_FILTER_FOR_ERRORS | 
                           FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS |
                           FLAGS_ERROR_UI_FLAGS_GENERATE_DATA,
                           NULL);

if (dwError == ERROR_INTERNET_FORCE_RETRY)
    goto resend;

// Insert code to read the data from the hResourceHandle
// at this point.

Dans l’exemple, dwErrorCode est utilisé pour stocker toutes les erreurs associées à l’appel à HttpSendRequest. HttpSendRequest se termine correctement, même si le proxy ou le serveur nécessite une authentification. Lorsque l’indicateur FLAGS_ERROR_UI_FILTER_FOR_ERRORS est passé à InternetErrorDlg, la fonction vérifie les en-têtes à la recherche d’erreurs masquées. Ces erreurs masquées incluent toutes les demandes d’authentification. InternetErrorDlg affiche la boîte de dialogue appropriée pour demander à l’utilisateur les données nécessaires. Les indicateurs FLAGS_ERROR_UI_FLAGS_GENERATE_DATA et FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS doivent également être transmis à InternetErrorDlg, afin que la fonction construise la structure de données appropriée pour l’erreur et stocke les résultats de la boîte de dialogue dans le handle HINTERNET .

L’exemple de code suivant montre comment l’authentification peut être gérée à l’aide d’InternetSetOption.

HINTERNET hOpenHandle,  hResourceHandle, hConnectHandle;
DWORD dwStatus;
DWORD dwStatusSize = sizeof(dwStatus);
char strUsername[64], strPassword[64];

// Normally, hOpenHandle, hResourceHandle,
// and hConnectHandle need to be properly assigned.

hOpenHandle = InternetOpen(TEXT("Example"),
                           INTERNET_OPEN_TYPE_PRECONFIG,
                           NULL, NULL, 0);
hConnectHandle = InternetConnect(hOpenHandle,
                                 TEXT("www.server.com"),
                                 INTERNET_INVALID_PORT_NUMBER,
                                 NULL,
                                 NULL,
                                 INTERNET_SERVICE_HTTP,
                                 0,0);

hResourceHandle = HttpOpenRequest(hConnectHandle, TEXT("GET"),
                                  TEXT("/premium/default.htm"),
                                  NULL, NULL, NULL,
                                  INTERNET_FLAG_KEEP_CONNECTION,
                                  0);

resend:

HttpSendRequest(hResourceHandle, NULL, 0, NULL, 0);

HttpQueryInfo(hResourceHandle, HTTP_QUERY_FLAG_NUMBER |
              HTTP_QUERY_STATUS_CODE, &dwStatus, &dwStatusSize, NULL);

switch (dwStatus)
{
    // cchUserLength is the length of strUsername and
    // cchPasswordLength is the length of strPassword.
    DWORD cchUserLength, cchPasswordLength;

    case HTTP_STATUS_PROXY_AUTH_REQ: // Proxy Authentication Required
        // Insert code to set strUsername and strPassword.

        // Insert code to safely determine cchUserLength and
        // cchPasswordLength. Insert appropriate error handling code.
        InternetSetOption(hResourceHandle,
                          INTERNET_OPTION_PROXY_USERNAME,
                          strUsername,
                          cchUserLength+1);

        InternetSetOption(hResourceHandle,
                          INTERNET_OPTION_PROXY_PASSWORD,
                          strPassword,
                          cchPasswordLength+1);
        goto resend;
        break;

    case HTTP_STATUS_DENIED:     // Server Authentication Required.
        // Insert code to set strUsername and strPassword.

        // Insert code to safely determine cchUserLength and
        // cchPasswordLength. Insert error handling code as
        // appropriate.
        InternetSetOption(hResourceHandle, INTERNET_OPTION_USERNAME,
                          strUsername, cchUserLength+1);
        InternetSetOption(hResourceHandle, INTERNET_OPTION_PASSWORD,
                          strPassword, cchPasswordLength+1);
        goto resend;
        break;
}

// Insert code to read the data from the hResourceHandle
// at this point.

Notes

WinINet ne prend pas en charge les implémentations de serveur. En outre, il ne doit pas être utilisé à partir d’un service. Pour les implémentations de serveur ou les services, utilisez Microsoft Windows HTTP Services (WinHTTP).