Manipulando a autenticação
Alguns proxies e servidores exigem autenticação antes de conceder acesso a recursos na Internet. As funções WinINet suportam autenticação de servidor e proxy para sessões http. A autenticação de servidores ftp deve ser gerida pela função InternetConnect. Atualmente, a autenticação de gateway FTP não é suportada.
Sobre a autenticação HTTP
Se a autenticação for necessária, o aplicativo cliente receberá um código de status 401, se o servidor exigir autenticação, ou 407, se o proxy exigir autenticação. Com o código de status, o proxy ou servidor envia um, ou mais, cabeçalhos de resposta autenticados —Proxy-Authenticate (para autenticação de proxy) ou WWW-Authenticate (para autenticação de servidor).
Cada cabeçalho de resposta autenticado contém um esquema de autenticação disponível e um domínio. Se houver suporte para vários esquemas de autenticação, o servidor retornará vários cabeçalhos de resposta de autenticação. O valor de realm é sensível a maiúsculas e minúsculas e define um espaço de proteção no proxy ou servidor. Por exemplo, o cabeçalho "WWW-Authenticate: Basic Realm="example"" seria um exemplo de um cabeçalho retornado quando a autenticação do servidor é necessária.
O aplicativo cliente que enviou a solicitação pode autenticar-se incluindo um campo de cabeçalho Autorização com a solicitação. O cabeçalho Autorização conteria o esquema de autenticação e a resposta apropriada exigida por esse esquema. Por exemplo, o cabeçalho "Authorization: Basic <username:password>" seria adicionado à solicitação e reenviado ao servidor se o cliente recebesse o cabeçalho de resposta autenticado "WWW-Authenticate: Basic Realm="example"".
Existem dois tipos gerais de esquemas de autenticação:
- Esquema de autenticação básica, onde o nome de usuário e a senha são enviados em texto não criptografado para o servidor.
- Esquemas de desafio-resposta, que possibilitam esse formato.
O esquema de autenticação Básica é baseado no modelo de que um cliente deve autenticar-se com um nome de usuário e senha para cada realm. O servidor atende a solicitação se ela for reenviada com um cabeçalho de Autorização que inclua um nome de usuário e senha válidos.
Os esquemas de desafio-resposta permitem uma autenticação mais segura. Se uma solicitação exigir autenticação usando um esquema de desafio-resposta, o código de status apropriado e os cabeçalhos de autenticação serão retornados ao cliente. O cliente deve, então, reenviar o pedido para negociar. O servidor retornaria um código de status apropriado com um desafio, e o cliente precisaria reenviar a solicitação com a resposta adequada para obter o serviço solicitado.
A tabela a seguir lista os esquemas de autenticação, o tipo de autenticação, a DLL que os suporta e uma descrição do esquema.
Para qualquer coisa diferente da autenticação básica, as chaves do Registro devem ser configuradas, além de instalar a DLL apropriada.
Se for necessária autenticação, deve ser usado o sinalizador INTERNET_FLAG_KEEP_CONNECTION na chamada a HttpOpenRequest. O sinalizador INTERNET_FLAG_KEEP_CONNECTION é necessário para NTLM e outros tipos de autenticação para manter a conexão durante a conclusão do processo de autenticação. Se a conexão não for mantida, o processo de autenticação deverá ser reiniciado com o proxy ou servidor.
As funções InternetOpenUrl e HttpSendRequest são concluídas com êxito, mesmo quando a autenticação é necessária. A diferença é que os dados retornados nos arquivos de cabeçalho e InternetReadFile receberiam uma página HTML informando o usuário sobre o código de status.
Registrando chaves de autenticação
INTERNET_OPEN_TYPE_PRECONFIG examina os valores do Registro ProxyEnable, ProxyServere ProxyOverride. Esses valores estão localizados em Software HKEY_CURRENT_USER\\Microsoft\Windows\CurrentVersion\Configurações da Internet.
Para esquemas de autenticação diferentes de Basic, uma chave deve ser adicionada ao registro em HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Security. Um valor DWORD, Flags, deve ser definido com o valor apropriado. A lista seguinte mostra os valores possíveis para o valor Flags.
PLUGIN_AUTH_FLAGS_UNIQUE_CONTEXT_PER_TCPIP (valor=0x01)
Cada soquete TCP/IP (Transmission Control Protocol/Internet Protocol) contém um contexto diferente. Caso contrário, um novo contexto será passado para cada modelo de URL de domínio ou bloco.
PLUGIN_AUTH_FLAGS_CAN_HANDLE_UI (valor=0x02)
Esta DLL pode lidar com a sua própria entrada de utilizador.
PLUGIN_AUTH_FLAGS_CAN_HANDLE_NO_PASSWD (valor=0x04)
Essa DLL pode ser capaz de fazer uma autenticação sem solicitar uma senha ao usuário.
PLUGIN_AUTH_FLAGS_NO_REALM (valor=0x08)
Esta DLL não usa uma cadeia de caracteres de realm http padrão. Quaisquer dados que parecem ser um domínio são dados específicos do esquema.
PLUGIN_AUTH_FLAGS_KEEP_ALIVE_NOT_REQUIRED (valor=0x10)
Esta DLL não requer uma conexão persistente para sua sequência de desafio-resposta.
Por exemplo, para adicionar autenticação NTLM, a chave NTLM deve ser adicionada ao HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Security. Em HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Security\NTLM, devem ser adicionados o valor string DLLFilee um valor DWORD , Flags. DLLFile deve ser definido como Winsspi.dlle Flags devem ser definidos como 0x08.
Autenticação do servidor
Quando um servidor recebe uma solicitação que requer autenticação, o servidor retorna uma mensagem de código de status 401. Nessa mensagem, o servidor deve incluir um ou mais cabeçalhos de resposta WWW-Authenticate. Esses cabeçalhos incluem os métodos de autenticação que o servidor tem disponíveis. WinINet escolhe o primeiro método que reconhece.
A autenticação básica fornece segurança fraca, a menos que o canal seja primeiro criptografado por link com SSL ou PCT.
A funçãoInternetErrorDlg pode ser usada para obter os dados de nome de usuário e senha do usuário, ou uma interface de usuário personalizada pode ser projetada para obter os dados.
Uma interface personalizada pode usar a função InternetSetOption para definir os valores INTERNET_OPTION_PASSWORD e INTERNET_OPTION_USERNAME e, em seguida, reenviar a solicitação para o servidor.
Autenticação de proxy
Quando um cliente tenta usar um proxy que requer autenticação, o proxy retorna uma mensagem de código de status 407 para o cliente. Nessa mensagem, o proxy deve incluir um ou mais cabeçalhos de resposta Proxy-Authenticate. Esses cabeçalhos incluem os métodos de autenticação disponíveis no proxy. WinINet escolhe o primeiro método que reconhece.
A função InternetErrorDlg pode ser usada para obter os dados de nome de usuário e senha do usuário, ou uma interface de usuário personalizada pode ser projetada.
Uma interface personalizada pode usar a funçãoInternetSetOption para definir os valores INTERNET_OPTION_PROXY_PASSWORD e INTERNET_OPTION_PROXY_USERNAME e, em seguida, reenviar a solicitação para o proxy.
Se nenhum nome de usuário e senha de proxy forem definidos, o WinINet tentará usar o nome de usuário e a senha para o servidor. Esse comportamento permite que os clientes implementem a mesma interface de usuário personalizada usada para manipular a autenticação do servidor.
Manipulando autenticação HTTP
A autenticação HTTP pode ser tratada com InternetErrorDlg ou uma função personalizada que utiliza InternetSetOption ou adiciona os seus próprios cabeçalhos de autenticação. InternetErrorDlg pode examinar os cabeçalhos associados a um identificador de HINTERNET para localizar erros ocultos, como códigos de status de um proxy ou servidor. InternetSetOption pode ser usado para definir o nome de usuário e senha para o proxy e servidor. Para autenticação MSN e DPA, InternetErrorDlg deve ser usado para definir o nome de usuário e a senha.
Para qualquer função personalizada que adicione seus próprios cabeçalhos WWW-Authenticate ou Proxy-Authenticate, o sinalizador INTERNET_FLAG_NO_AUTH deve ser definido para desabilitar a autenticação.
O exemplo a seguir mostra como InternetErrorDlg pode ser usado para manipular a autenticação 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.
No exemplo, dwErrorCode é usado para armazenar quaisquer erros associados à chamada para HttpSendRequest. HttpSendRequest é concluído com êxito, mesmo que o proxy ou servidor exija autenticação. Quando o sinalizador FLAGS_ERROR_UI_FILTER_FOR_ERRORS é passado para InternetErrorDlg , a função verifica os cabeçalhos em busca de erros ocultos. Esses erros ocultos incluiriam quaisquer solicitações de autenticação. InternetErrorDlg exibe a caixa de diálogo apropriada para solicitar ao usuário os dados necessários. Os sinalizadores FLAGS_ERROR_UI_FLAGS_GENERATE_DATA e FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS também devem ser passados para InternetErrorDlg, para que a função crie a estrutura de dados apropriada para o erro e armazene os resultados da caixa de diálogo no manipulador HINTERNET.
O código de exemplo a seguir mostra como a autenticação pode ser tratada usando 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.
Observação
WinINet não suporta implementações de servidor. Além disso, não deve ser usado num serviço. Para implementações ou serviços de servidor, use Microsoft Windows HTTP Services (WinHTTP).