vba authentication https winhttp

vba - No entiendo por qué WinHTTP NO autentica cierto recurso HTTPS



authentication (3)

Estaría muy agradecido por cualquier tipo de ayuda que pueda ayudarme a resolver el problema.

Desde el código de Excel VBA, necesito descargar y analizar el archivo CSV del sitio HTTPS https://redmine.itransition.com/ . Intento usar WinHTTP para obtener el archivo. Sin embargo, no puedo entender por qué la autenticación no funciona. Aquí está la pieza de código relacionado:

TargetURL = "https://redmine.itransition.com/projects/pmct/time_entries.csv" Set HTTPReq = CreateObject("WinHttp.WinHttpRequest.5.1") HTTPReq.Option(4) = 13056 '' WinHttpRequestOption_SslErrorIgnoreFlags 13056: ignore all err, 0: accept no err HTTPReq.Open "GET", TargetURL, False HTTPReq.SetCredentials "UN", "PW", 0 HTTPReq.send

devuelve la siguiente respuesta (solo se enumeran ciertas cadenas):

Content-Type: text/html; charset=utf-8 Status: 406 X-Runtime: 5

Sin embargo, si envío cadena de "Cookie" desde la cookie de Firefox después de una autenticación manual exitosa usando

HTTPReq.setRequestHeader "Cookie", SetCookieString HTTPReq.send

Obtuve fácilmente el archivo esperado. Por supuesto, no estoy contento con esa solución y quiero realizar una verdadera autenticación WinHTTP. Sin embargo, no puedo entender qué pasa o qué extraño en mi código. Lo más probable es que tenga que usar el método .SetClientCertificate , pero esto no está claro para mí, ¿qué certificado es obligatorio?

O, siendo más general: ¿qué métodos o funciones de WinHTTP debo usar para la depuración para descubrir qué paso es el bloqueo / incorrecto y me impide una autenticación correcta? Pasé 2 semanas buscando a través de MSDN y varios recursos, pero todavía no tengo solución.

¡Gracias por adelantado por tus sugerencias!


El inicio de sesión en https://redmine.itransition.com/ es solo un formulario HTML que publica un nombre de usuario y contraseña para un script en /login .

Esto no es compatible con SetCredentials que está diseñado para esquemas de autenticación basados ​​en servidor como basic / digest / ntlm.

Debe cargar esa página sin credenciales, tomar lo que se parece al campo volátil authenticity_token del formulario generado y publicarlo junto con el nombre de usuario y la contraseña para /login .

Si se trata de un sistema basado en sesión, responderá con el encabezado de la cookie set + los datos que necesita utilizar en la solicitud posterior.


¡La respuesta anterior de @Alex K. fue exactamente lo que estaba buscando por mucho tiempo! Con la ayuda de Firebug y MSDN terminé con 3 solicitudes:

  • Solicitud GET para recopilar datos de autenticidad_token de la página de inicio de sesión usando RegEx
  • Solicitud POST para autenticar y recopilar la cadena de cookies requerida de la respuesta
  • OBTENER la solicitud para finalmente obtener mi amado CSV

La siguiente pieza de código que está funcionando como se esperaba:

Set RegX_AuthToken = CreateObject("VBScript.RegExp") '' Below Pattern w/o double-quotes encoded: (?:input name="authenticity_token" type="hidden" value=")(.*)(?:") RegX_AuthToken.Pattern = "(?:input name=" & Chr(34) & "authenticity_token" & Chr(34) & " type=" & Chr(34) & "hidden" & Chr(34) & " value=" & Chr(34) & ")(.*)(?:" & Chr(34) & ")" RegX_AuthToken.IgnoreCase = True RegX_AuthToken.Global = True TargetURL = "https://redmine.itransition.com/login" Set HTTPReq = CreateObject("WinHttp.WinHttpRequest.5.1") HTTPReq.Open "GET", TargetURL, False HTTPReq.Send Set Token_Match = RegX_AuthToken.Execute(HTTPReq.ResponseText) AuthToken = Token_Match.Item(0).SubMatches.Item(0) PostData = "authenticity_token=" & AuthToken & "&back_url=https://redmine.itransition.com/" & "&username=" & UN & "&password=" & PW & "&login=Login »" HTTPReq.Open "POST", TargetURL, False HTTPReq.setRequestHeader "Content-Type", "application/x-www-form-urlencoded" HTTPReq.Send (PostData) SetCookieString = HTTPReq.GetResponseHeader("Set-Cookie") TargetURL = "https://redmine.itransition.com/projects/pmct/time_entries.csv" HTTPReq.Open "GET", TargetURL, False HTTPReq.setRequestHeader "Cookie", SetCookieString HTTPReq.Send

La siguiente URL fue útil para generar solicitudes POST: http://tkang.blogspot.com/2010/09/sending-http-post-request-with-vba.html

Debe cargar esa página sin credenciales, tomar lo que se parece al campo volátil authenticity_token del formulario generado y publicarlo junto con el nombre de usuario y la contraseña para / iniciar sesión.

Alex K. - ¡gracias de nuevo por la brillante sugerencia! (:


Y una cosa más (además de la solución anterior) uno debe tener en cuenta en caso de usar solicitudes POST similares al código anterior: por alguna razón oscura todavía recibí una vez en 4-5 veces (o incluso más) el odiado 406 respuesta del sitio web, lo que significa que en mi caso, la autenticación NO está completa . Después de horas de depuración paso a paso, descubrí felizmente la causa: el valor del token auth puede tener + signos, y al analizar una flecha de varias docenas de tokens / códigos de respuesta, descubrí que los tokens que contienen + coinciden exactamente con los 406 códigos.

La solución se volvió bastante obvia: codificaciones URL seguras para PostData . Con la ayuda de http://www.blooberry.com/indexdot/html/topics/urlencoding.htm finalmente llegué a lo siguiente:

PostData = "authenticity_token=" & Replace(AuthToken, "+", "%2B", vbTextCompare) & _ "&back_url=https://redmine.itransition.com/projects/" & Trim(RedmineProject) & _ "/time_entries" & "&username=" & UN & "&password=" & PW & "&login=Login »"

+ es reemplazado por %2B s, y esto fue todo, ¡no más 406!)

Los otros caracteres especiales no importan en mi caso, pero la lección fue aprendida. Espero que esto le ahorrará varias horas de vida a otra persona.