Use Invoke-WebRequest com um nome de usuário e senha para autenticação básica na API do GitHub

127

Com cURL, podemos passar um nome de usuário com uma solicitação da Web HTTP da seguinte maneira:

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

A -ubandeira aceita um nome de usuário para autenticação e, em seguida, o cURL solicitará a senha. O exemplo cURL é para autenticação básica com a API do GitHub .

Como passamos da mesma forma um nome de usuário e senha junto com Invoke-WebRequest? O objetivo final é o usuário do PowerShell com autenticação básica na API do GitHub.

Shaun Luttin
fonte
$ pair deve ser $pair = "$($user):$($pass)"Verifique a resposta aprovada. Eu estava usando o exposto, e isso me deu muita dor
Bhavjot
Nenhuma das soluções que sugerem a -Credentialabordagem funciona como o cabeçalho de autenticação correto não é gerada quando a solicitação é feita.
StingyJack
@ Shaun Luttin - Este é um site de perguntas e respostas, não um site de perguntas e respostas. Esse usuário prefere ver uma pergunta sucinta como possível e respostas que não sejam o que funcionou para sua situação específica, mas não tendo que lê-la duas vezes (uma vez na pergunta editada, agora vem o QuestionAnswer e, em seguida, novamente nas respostas). Se a preocupação foi a resposta que ajudou você a não se aproximar mais da pergunta, o StackExchange possui funcionalidade para aproximar a melhor / aceita a mais próxima possível da pergunta.
user66001
1
@ user66001 Obrigado pelo feedback. Mudei minha resposta em questão para sua própria resposta para referência posterior. Eu acho que isso é uma melhoria.
Shaun Luttin
@ShaunLuttin - Ótima idéia! :)
user66001

Respostas:

147

Estou assumindo autenticação básica aqui.

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

Você pode obter sua credencial por outros meios ( Import-Clixml, etc.), mas ela precisa ser um [PSCredential]objeto.

Edite com base nos comentários:

O GitHub está quebrando o RFC, conforme explicado no link que você forneceu :

A API suporta autenticação básica, conforme definido na RFC2617, com algumas pequenas diferenças. A principal diferença é que o RFC exige que solicitações não autenticadas sejam respondidas com 401 respostas não autorizadas. Em muitos lugares, isso revelaria a existência de dados do usuário. Em vez disso, a API do GitHub responde com 404 não encontrado. Isso pode causar problemas para bibliotecas HTTP que assumem uma resposta 401 não autorizada. A solução é criar manualmente o cabeçalho da autorização.

Pelo que sei, o Powershell's Invoke-WebRequestespera uma resposta 401 antes de enviar as credenciais, e como o GitHub nunca fornece uma, suas credenciais nunca serão enviadas.

Crie manualmente os cabeçalhos

Em vez disso, você precisará criar os cabeçalhos de autenticação básicos.

A autenticação básica utiliza uma sequência que consiste no nome de usuário e na senha separados por dois pontos user:passe envia o resultado codificado em Base64.

Código como este deve 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

Você poderia combinar parte da concatenação de cadeias, mas eu queria quebrá-la para torná-la mais clara.

briantist
fonte
1
Como eu disse, funciona para autenticação básica, mas não sei que tipo de autenticação a API do GitHub usa. Você pode postar alguns detalhes sobre o que é esperado e isso pode nos ajudar a resolver o problema.
Briantist
1
Ah, parece que o GitHub (por sua própria admissão) não segue o RFC, mas o Powershell está. Editei a resposta com mais informações e uma solução alternativa.
Brianista
1
Sim, se você estiver fazendo muitos desses tipos de chamadas, recomendo agrupar isso em uma função. Como eu disse, realmente estalei todas as peças para maior clareza, mas você poderia fazer tudo em uma linha (seria apenas uma bagunça).
Briantist
1
@ Aref, você deve postar uma nova pergunta com o código que está usando. Se você fizer isso e me avise, eu darei uma olhada.
Briantist
1
Você vai precisar para construir manualmente os cabeçalhos se a tentar a autenticação contra o API Visual Studio Team serviços REST também
Brent Robinson
44

Usa isto:

$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
fonte
Por algum motivo, a resposta selecionada não funcionou para mim ao usá-la no TFS vNext, mas essa foi a solução. Muito obrigado!
amigos estão dizendo sobre tybs
A resposta selecionada não funcionou para executar um runbook do PowerShell no azure para iniciar um trabalho acionado, mas essa resposta funcionou.
Sam
7

Eu tive que fazer isso para fazê-lo funcionar:

$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
fonte
6

Invoke-WebRequestsegue o RFC2617 como observou o @briantist, no entanto, existem alguns sistemas (por exemplo, JFrog Artifactory) que permitem o uso anônimo se o Authorizationcabeçalho estiver ausente, mas responderão 401 Forbiddense o cabeçalho contiver credenciais inválidas.

Isso pode ser usado para acionar a 401 Forbiddenresposta e começar -Credentialsa trabalhar.

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

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

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

Isso enviará o cabeçalho inválido na primeira vez, que será substituído pelas credenciais válidas na segunda solicitação, uma vez que -Credentialssubstitui o Authorizationcabeçalho.

Testado com o PowerShell 5.1

Leonard Brünings
fonte
5

Se alguém precisaria de um forro:

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

outra maneira é usar certutil.exe, salve seu nome de usuário e senha em um arquivo, por exemplo, in.txt como nome de usuário: senha

certutil -encode in.txt out.txt

Agora você deve poder usar o valor de autenticação de out.txt

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

Sei que isso está um pouco fora da solicitação original dos OPs, mas me deparei com isso enquanto procurava uma maneira de usar o Invoke-WebRequest em um site que requer autenticação básica.

A diferença é que eu não queria gravar a senha no script. Em vez disso, eu queria solicitar credenciais ao gerenciador de scripts para o site.

Aqui está como eu lidei com isso

$creds = Get-Credential

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

Invoke-WebRequest -Uri $URL -Credential $basicCreds

O resultado é que o script script é solicitado com uma caixa de diálogo de logon para a U / P; Invoke-WebRequest pode acessar o site com essas credenciais. Isso funciona porque $ Creds.Password já é uma sequência criptografada.

Espero que isso ajude alguém a procurar uma solução semelhante à pergunta acima, mas sem salvar o nome de usuário ou o PW no script

Ernest Correale
fonte
0

Foi isso que funcionou para a nossa situação particular.

As anotações são da Wikipedia sobre autenticação básica do lado do cliente . Obrigado à resposta do @ briantist pela ajuda!

Combine o nome de usuário e a senha em uma única sequência username:password

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

Codifique a string para a variante RFC2045-MIME da Base64, exceto não se limitando a 76 caracteres / linha.

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

Crie o valor Auth como o método, um espaço e, em seguida, o par codificado Method Base64String

$basicAuthValue = "Basic $base64"

Crie o cabeçalho Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

$headers = @{ Authorization = $basicAuthValue }

Invocar a solicitação da web

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

A versão do PowerShell é mais detalhada que a versão cURL. Por que é que? O @briantist apontou que o GitHub está quebrando o RFC e o PowerShell está aderindo a ele. Isso significa que o cURL também está rompendo com o padrão?

Shaun Luttin
fonte