Use Invoke-WebRequest con un nombre de usuario y contraseña para la autenticación básica en la API de GitHub

127

Con cURL, podemos pasar un nombre de usuario con una solicitud web HTTP de la siguiente manera:

$ curl -u <your_username> https://api.github.com/user

La -ubandera acepta un nombre de usuario para la autenticación, y luego cURL solicitará la contraseña. El ejemplo de cURL es para la autenticación básica con la API de GitHub .

¿Cómo pasamos de manera similar un nombre de usuario y contraseña junto con Invoke-WebRequest? El objetivo final es usar PowerShell con autenticación básica en la API de GitHub.

Shaun Luttin
fuente
$ par debe ser $pair = "$($user):$($pass)"Compruebe la respuesta aprobada. Estaba usando lo anterior y me dio demasiado dolor
Bhavjot
Ninguna de las soluciones que sugieren que el -Credentialenfoque funcione como el encabezado de autenticación correcto no se genera cuando se realiza la solicitud.
StingyJack
@Shaun Luttin: este es un sitio de preguntas y respuestas, no un sitio de preguntas y respuestas. Este usuario preferiría ver una breve y posible pregunta y respuestas diferentes a las que funcionaron para su situación particular, pero no tener que leer eso dos veces (una vez en la pregunta editada, ahora viene QuestionAnswer y luego nuevamente en las respuestas). Si la preocupación fue la respuesta que le ayudó a no estar más cerca de la pregunta, StackExchange tiene la funcionalidad para llevar la respuesta mejor / aceptada lo más cerca posible de la pregunta ya.
user66001
1
@ user66001 Gracias por los comentarios. He movido mi respuesta en pregunta a su propia respuesta para referencia posterior. Creo que esto es una mejora.
Shaun Luttin
@ShaunLuttin - ¡Gran idea! :)
user66001

Respuestas:

147

Estoy asumiendo la autenticación básica aquí.

$cred = Get-Credential
Invoke-WebRequest -Uri 'https://whatever' -Credential $cred

Puede obtener su credencial a través de otros medios ( Import-Clixml, etc.), pero tiene que ser un [PSCredential]objeto.

Editar basado en comentarios:

GitHub está rompiendo RFC como explican en el enlace que proporcionó :

La API admite la autenticación básica como se define en RFC2617 con algunas pequeñas diferencias. La principal diferencia es que el RFC requiere que las solicitudes no autenticadas sean respondidas con 401 respuestas no autorizadas. En muchos lugares, esto revelaría la existencia de datos del usuario. En cambio, la API de GitHub responde con 404 No encontrado. Esto puede causar problemas para las bibliotecas HTTP que asumen una respuesta no autorizada 401. La solución es crear manualmente el encabezado de autorización.

Powershell, Invoke-WebRequestsegún mi conocimiento, espera una respuesta 401 antes de enviar las credenciales, y dado que GitHub nunca proporciona una, sus credenciales nunca se enviarán.

Construir manualmente los encabezados

En su lugar, deberá crear los encabezados de autenticación básicos usted mismo.

La autenticación básica toma una cadena que consiste en el nombre de usuario y la contraseña separados por dos puntos user:passy luego envía el resultado codificado en Base64 de eso.

Un código como este debería funcionar:

$user = 'user'
$pass = 'pass'

$pair = "$($user):$($pass)"

$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))

$basicAuthValue = "Basic $encodedCreds"

$Headers = @{
    Authorization = $basicAuthValue
}

Invoke-WebRequest -Uri 'https://whatever' -Headers $Headers

Podrías combinar algunas de las concatenaciones de cuerdas, pero quería separarlas para aclararlas.

briantista
fuente
1
Como dije, funciona para la autenticación básica, pero no sé qué tipo de autenticación usa la API de GitHub. Puede publicar algunos detalles sobre lo que se espera y que podría ayudarnos a resolver el problema.
briantist
1
Ah, parece que GitHub (por su propia admisión) no sigue RFC, pero Powershell sí. He editado la respuesta con más información y una solución alternativa.
briantist
1
Sí, si vas a hacer un montón de este tipo de llamadas, te recomendaría incluir esto en una función. Como ya he dicho que realmente rompió todas las piezas para mayor claridad, pero que podía hacerlo todo en una línea (que sólo sería desordenado).
briantist
1
@Aref, debes publicar una nueva pregunta con el código que estás usando. Si lo haces y me avisas, echaré un vistazo.
briantist
1
Tendrá que construir manualmente los encabezados si intenta la autenticación en la API REST de Visual Studio Team Services también
Brent Robinson el
44

Utilizar este:

$root = 'REST_SERVICE_URL'
$user = "user"
$pass= "password"
$secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($user, $secpasswd)

$result = Invoke-RestMethod $root -Credential $credential
mfralou
fuente
Por alguna razón, la respuesta seleccionada no funcionó para mí cuando la usé en TFS vNext, pero esta fue la solución. ¡Muchas gracias!
Tybs el
La respuesta seleccionada no funcionó para ejecutar un runbook de PowerShell en azul para iniciar un trabajo desencadenado, pero esta respuesta funcionó.
Sam
7

Tuve que hacer esto para que funcione:

$pair = "$($user):$($pass)"
$encodedCredentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($Pair))
$headers = @{ Authorization = "Basic $encodedCredentials" }
Invoke-WebRequest -Uri $url -Method Get -Headers $headers -OutFile Config.html
livy111
fuente
6

Invoke-WebRequestsigue el RFC2617 como señaló @briantist, sin embargo, hay algunos sistemas (por ejemplo, JFrog Artifactory) que permiten el uso anónimo si el Authorizationencabezado está ausente, pero responderán 401 Forbiddensi el encabezado contiene credenciales no válidas.

Esto se puede utilizar para activar la 401 Forbiddenrespuesta y ponerse -Credentialsa trabajar.

$login = Get-Credential -Message "Enter Credentials for Artifactory"

                              #Basic foo:bar
$headers = @{ Authorization = "Basic Zm9vOmJhcg==" }  

Invoke-WebRequest -Credential $login -Headers $headers -Uri "..."

Esto enviará el encabezado no válido la primera vez, que se reemplazará con las credenciales válidas en la segunda solicitud, ya que -Credentialsanula el Authorizationencabezado.

Probado con Powershell 5.1

Leonard Brünings
fuente
5

Si alguien necesitara un trazador de líneas:

iwr -Uri 'https://api.github.com/user' -Headers @{ Authorization = "Basic "+ [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("user:pass")) }
karolberezicki
fuente
2

otra forma es usar certutil.exe, guarde su nombre de usuario y contraseña en un archivo, por ejemplo, in.txt como nombre de usuario: contraseña

certutil -encode in.txt out.txt

Ahora debería poder usar el valor de autenticación de out.txt

$headers = @{ Authorization = "Basic $((get-content out.txt)[1])" }
Invoke-WebRequest -Uri 'https://whatever' -Headers $Headers
mayursharma
fuente
2

Sé que esto está un poco fuera de la solicitud original de los OP, pero me encontré con esto mientras buscaba una forma de usar Invoke-WebRequest en un sitio que requiere autenticación básica.

La diferencia es que no quería registrar la contraseña en el script. En cambio, quería solicitar al creador de guiones las credenciales para el sitio.

Así es como lo manejé

$creds = Get-Credential

$basicCreds = [pscredential]::new($Creds.UserName,$Creds.Password)

Invoke-WebRequest -Uri $URL -Credential $basicCreds

El resultado es que se le solicita al corredor de secuencias de comandos un cuadro de diálogo de inicio de sesión para U / P y luego, Invoke-WebRequest puede acceder al sitio con esas credenciales. Esto funciona porque $ Creds.Password ya es una cadena encriptada.

Espero que esto ayude a alguien que busque una solución similar a la pregunta anterior pero sin guardar el nombre de usuario o PW en el script

Ernest Correale
fuente
0

Esto es lo que funcionó para nuestra situación particular.

Las notas son de Wikipedia sobre autenticación básica del lado del cliente . ¡Gracias a la respuesta de @briantist por la ayuda!

Combina el nombre de usuario y la contraseña en una sola cadena username:password

$user = "shaunluttin"
$pass = "super-strong-alpha-numeric-symbolic-long-password"
$pair = "${user}:${pass}"

Codifique la cadena a la variante RFC2045-MIME de Base64, excepto que no se limita a 76 caracteres / línea.

$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$base64 = [System.Convert]::ToBase64String($bytes)

Cree el valor de Auth como método, un espacio y luego el par codificado Method Base64String

$basicAuthValue = "Basic $base64"

Crea el encabezado Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

$headers = @{ Authorization = $basicAuthValue }

Invocar la solicitud web

Invoke-WebRequest -uri "https://api.github.com/user" -Headers $headers

La versión de PowerShell de esto es más detallada que la versión cURL. ¿Porqué es eso? @briantist señaló que GitHub está rompiendo el RFC y PowerShell se apega a él. ¿Eso significa que cURL también está rompiendo con el estándar?

Shaun Luttin
fuente