I've seen articles about manipulating files with Google Drive using a personal OAuth2 token in PowerShell, but not with domain-wide privileges.
From what I understand, the workflow goes like this:
I'm having issues with step 3. Please see the below code:
$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
The errors I'm getting are indicating a bad JWT signature. The secret key Google is providing is in PEM format, but I'm having issues translating it into something Powershell can understand.
I was having the same issue for a while until I came across using the OWIN libraries to do it.
Here's the link to my Get-GSToken function that's part of my PSGSuite module. You can tear this apart if you'd like to do what you need (the purpose of that function is to grab a token), but you'll need the nuget
folder as well in order for it to work (OWIN libraries are contained in there):
https://github.com/nferrell/PSGSuite/blob/master/Public/Get-GSToken.ps1
Feel free to grab the entire module for samples! I've wrapped almost all of the Google API calls into Powershell functions in there, all leveraging Get-GSToken
to first grab a token at the scope the function needs.
Something to note: this leverages a service account and a P12 key file, not the clientsecrets.json file key type. I'm not sure how to build a working JWT with pure Powershell using the JSON file, but the P12 + OWIN libraries work amazingly well for it.