尝试使用Google Drive API的JWT签名错误

时间:2017-05-12 18:38:14

标签: api powershell google-drive-api oauth2-playground

我见过有关使用PowerShell中的个人OAuth2令牌使用Google云端硬盘操纵文件的文章,但没有使用域范围的权限。

据我所知,工作流程如下:

  1. 创建标题base64 encode
  2. 创建声明base64 encode
  3. 合并标题和声明,然后使用RSA256和Google提供的私钥
  4. 进行签名

    我遇到了第3步的问题。请参阅以下代码:

    $firstdate = Get-Date -Year 1970 -Month 1 -Day 1 -Hour 0 -Minute 0 -Second 0 -Millisecond 0
    $endtime = (New-TimeSpan -Start $firstdate -End (Get-Date).AddMinutes(30).ToUniversalTime()).TotalSeconds
    $issuetime = (New-TimeSpan -Start $firstdate -End (Get-Date).ToUniversalTime()).TotalSeconds
    $jsonfile = Get-Content 'secret_file.json' | ConvertFrom-Json
    
    $headerhash = [ordered]@{
        'alg' = 'RS256'
        'typ' = 'JWT'
    }
    $headerjson = $headerhash | ConvertTo-Json -Compress
    $encodedheader = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($headerjson))
    
    $claimhash = [ordered]@{
        'iss' = $jsonfile.client_email
        'scope' = 'https://www.googleapis.com/auth/drive'
        'aud' = 'https://www.googleapis.com/oauth2/v4/token'
        'exp' = [math]::Round($endtime,0)
        'iat' = [math]::Round($issuetime,0)
    }
    $claimjson = $claimhash | ConvertTo-Json -Compress
    $encodedclaim = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($claimjson))
    
    #$sha = [System.Security.Cryptography.RSACryptoServiceProvider]::Create()
    #$sha.Key = [System.Text.Encoding]::UTF8.Getbytes($jsonfile.private_key)
    #$sha.FromXmlString($sha.ToXmlString($jsonfile.private_key))
    #$signature = $sha.ComputeHash([System.Text.Encoding]::UTF8.GetBytes("$encodedheader.$encodedclaim"))
    #$signature = $sha.SignData([System.Text.Encoding]::UTF8.GetBytes("$encodedheader.$encodedclaim"),[System.Security.Cryptography.CryptoConfig]::MapNameToOID('RSASSA-PKCS1-V1_5-SIGN'))
    #$encodedsignature = [System.Convert]::ToBase64String($signature)
    #$formatter = [System.Security.Cryptography.RSAPKCS1SignatureFormatter]::new($sha)
    #$formatter.SetKey($sha)
    #$formatter.CreateSignature([System.Text.Encoding]::UTF8.GetBytes("$encodedheader.$encodedclaim"))
    
    $jws = "$encodedheader.$encodedclaim"
    $encodedjws = [System.Text.Encoding]::UTF8.GetBytes($jws)
    
    $rsa = [System.Security.Cryptography.RSACryptoServiceProvider]::Create()
    # This is the key -- need to convert PEM to proper format
    $rsa.FromXmlString($rsa.ToXmlString($jsonfile.private_key))
    $sha256OID = [System.Security.Cryptography.CryptoConfig]::MapNameToOID("SHA256")
    $signature = $rsa.SignData($encodedjws,$sha256OID)
    $encodedsignature = [System.Convert]::ToBase64String($signature)
    
    $jwt = "$encodedheader.$encodedclaim.$encodedsignature"
    
    $requestUri = 'https://www.googleapis.com/oauth2/v4/token'
    $method = 'POST'
    $body = [ordered]@{
        'grant_type' = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
        'assertion' = $jwt
    }
    Invoke-webrequest -Uri $requestUri -Method $method -Body $body -ContentType application/x-www-form-urlencoded
    

    我得到的错误表明JWT签名错误。谷歌提供的秘密密钥是采用PEM格式,但我遇到的问题是将其翻译成Powershell可以理解的内容。

1 个答案:

答案 0 :(得分:0)

我有一段时间遇到同样的问题,直到我遇到使用OWIN库来完成它。

这是我的Get-GSToken功能的链接,这是我的PSGSuite模块的一部分。如果你想做你需要的东西(这个功能的目的是获取一个令牌),你可以将它拆开,但你也需要nuget文件夹以便它工作(OWIN库包含在那里):

https://github.com/nferrell/PSGSuite/blob/master/Public/Get-GSToken.ps1

随意抓取整个模块的样品!我已将几乎所有的Google API调用都包含在其中的Powershell函数中,所有人都利用Get-GSToken首先在函数所需的范围内获取令牌。

需要注意的事项:这会利用服务帐户和P12密钥文件,而不是clientsecrets.json文件密钥类型。我不确定如何使用JSON文件使用纯Powershell构建一个可用的JWT,但是P12 + OWIN库的工作效果非常好。