Google Identity Platform:使用 Firebase Admin SDK 私钥在 Powershell 中使用 OAuth 2.0 - powershell - SO中文参考 (2024)

尝试使用 Powershell HTTP/REST 并遵循本教程来实现 Firebase Admin SDK 服务帐户访问(Powershell 中没有方便的 API);

将 OAuth 2.0 用于服务器到服务器应用程序

形成 JWT 标头和 JWT 声明集非常简单,我可以重现教程中的示例,但这就是棘手的地方;

使用 SHA256withRSA(也称为带有 SHA-256 哈希函数的 RSASSA-PKCS1-V1_5-SIGN)以及从 Google API 控制台获取的私钥对输入的 UTF-8 表示形式进行签名。输出将是一个字节数组。签名必须经过 Base64url 编码

2023 年 6 月 28 日决议,工作完成(5 年后)

JSON Web 令牌库上有两个 Powershell 库,它们可以很好地为 Google 服务器到服务器服务创建所需的签名。

我怀疑问题在于使用正确的公钥和私钥初始化 RSACryptoServiceProvider,这些密钥已作为 JSON 对象提供。您调用的

.toXML()

方法可能不起作用。

这个问题中有一些关于如何设置自己的公钥/私钥的讨论,这可能是一条可行的道路。

您可以尝试生成一个新的密钥对,并在结果上按

.toXML($true)

以查看 XML 的格式如何,然后将基于 JSON 的密钥数据调整为该格式。

编辑

经过研究,您面临的挑战是将 Google 提供的 PKCS#8 编码密钥转换为 RSACryptoServiceProvider 可以使用的形式。 .NET 目前没有用于读取此密钥的 API,但有兴趣纠正此缺陷。

一种似乎有效的解决方法是为您的服务帐户生成 P12 密钥。如果无法创建新的服务帐户,可以通过多种方法将 .json 文件中的私钥文件转换为 P12

我使用 p12 密钥创建了一个新的服务帐户,并且用于签名的 powershell 代码比以前更简单:

$certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($p12file,'thepasswordforthekeystore')$dataToSign = "This is some data"$certificate.privateKey.SignData( [system.text.encoding]::utf8.getbytes($dataToSign), [System.Security.Cryptography.HashAlgorithmName]::SHA256, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1)

 

1
投票

在寻找如何通过 PowerShell 使用 GCP 服务帐户 json 文件的方法几个小时后,发现了这篇文章,解释了 OpenSSL pem 格式和 ImportCspBlob 理解的 Microsoft CryptoAPI 之间的区别。

https://www.sysadmins.lv/blog-en/how-to-convert-pem-file-to-a-cryptoapi-known-format.aspx

经过一些细微修改,这里是我在 PowerShell 脚本中使用的代码:

function Get-ASNLength ($RawData, $offset) { $return = "" | Select FullLength, Padding, LengthBytes, PayLoadLength if ($RawData[$offset + 1] -lt 128) { $return.lengthbytes = 1 $return.Padding = 0 $return.PayLoadLength = $RawData[$offset + 1] $return.FullLength = $return.Padding + $return.lengthbytes + $return.PayLoadLength + 1 } else { $return.lengthbytes = $RawData[$offset + 1] - 128 $return.Padding = 1 $lengthstring = -join ($RawData[($offset + 2)..($offset + 1 + $return.lengthbytes)] | %{"{0:x2}" -f $_}) $return.PayLoadLength = Invoke-Expression 0x$($lengthstring) $return.FullLength = $return.Padding + $return.lengthbytes + $return.PayLoadLength + 1 } $return}function Get-NormalizedArray ($array) { $padding = $array.Length % 8 if ($padding) { $array = $array[$padding..($array.Length - 1)] } [array]::Reverse($array) [Byte[]]$array}function Convert-OpenSSLPrivateKey ($key) { if ($key -match "(?msx).*-{5}BEGIN\sPRIVATE\sKEY-{5}(.+)-{5}END\sPRIVATE\sKEY-{5}") { Write-Debug "Processing Private Key module." $Bytes = [Convert]::FromBase64String($matches[1]) if ($Bytes[0] -eq 48) {Write-Debug "Starting asn.1 decoding."} else {Write-Warning "The data is invalid."; return} $offset = 0 # main sequence Write-Debug "Process outer Sequence tag." $return = Get-ASNLength $Bytes $offset Write-Debug "outer Sequence length is $($return.PayloadLength) bytes." $offset += $return.FullLength - $return.PayloadLength Write-Debug "New offset is: $offset" # zero integer Write-Debug "Process zero byte" $return = Get-ASNLength $Bytes $offset Write-Debug "outer zero byte length is $($return.PayloadLength) bytes." $offset += $return.FullLength Write-Debug "New offset is: $offset" # algorithm identifier Write-Debug "Proess algorithm identifier" $return = Get-ASNLength $Bytes $offset Write-Debug "Algorithm identifier length is $($return.PayloadLength) bytes." $offset += $return.FullLength Write-Debug "New offset is: $offset" # octet string $return = Get-ASNLength $Bytes $offset Write-Debug "Private key octet string length is $($return.PayloadLength) bytes." $offset += $return.FullLength - $return.PayLoadLength Write-Debug "New offset is: $offset" } elseif ($key -match "(?msx).*-{5}BEGIN\sRSA\sPRIVATE\sKEY-{5}(.+)-{5}END\sRSA\sPRIVATE\sKEY-{5}") { Write-Debug "Processing RSA KEY module." $Bytes = [Convert]::FromBase64String($matches[1]) if ($Bytes[0] -eq 48) {Write-Debug "Starting asn.1 decoding"} else {Write-Warning "The data is invalid"; return} $offset = 0 Write-Debug "New offset is: $offset" } else {Write-Warning "The data is invalid"; return} # private key sequence Write-Debug "Process private key sequence." $return = Get-ASNLength $Bytes $offset Write-Debug "Private key length (including inner ASN.1 tags) is $($return.PayloadLength) bytes." $offset += $return.FullLength - $return.PayLoadLength Write-Debug "New offset is: $offset" # zero integer Write-Debug "Process zero byte" $return = Get-ASNLength $Bytes $offset Write-Debug "Zero byte length is $($return.PayloadLength) bytes." $offset += $return.FullLength Write-Debug "New offset is: $offset" # modulus Write-Debug "Processing private key modulus." $return = Get-ASNLength $Bytes $offset Write-Debug "Private key modulus length is $($return.PayloadLength) bytes." $modulus = $Bytes[($offset + $return.FullLength - $return.PayLoadLength)..($offset + $return.FullLength - 1)] $modulus = Get-NormalizedArray $modulus $offset += $return.FullLength Write-Debug "New offset is: $offset" # public exponent Write-Debug "Process private key public exponent." $return = Get-ASNLength $Bytes $offset Write-Debug "Private key public exponent length is $($return.PayloadLength) bytes." Write-Debug "Private key public exponent padding is $(4 - $return.PayLoadLength) byte(s)." $padding = New-Object byte[] -ArgumentList (4 - $return.PayLoadLength) [Byte[]]$PublicExponent = $padding + $Bytes[($offset + $return.FullLength - $return.PayLoadLength)..($offset + $return.FullLength - 1)] $offset += $return.FullLength Write-Debug "New offset is: $offset" # private exponent Write-Debug "Process private key private exponent." $return = Get-ASNLength $Bytes $offset Write-Debug "Private key private exponent length is $($return.PayloadLength) bytes." $PrivateExponent = $Bytes[($offset + $return.FullLength - $return.PayLoadLength)..($offset + $return.FullLength - 1)] $PrivateExponent = Get-NormalizedArray $PrivateExponent $offset += $return.FullLength Write-Debug "New offset is: $offset" # prime1 Write-Debug "Process Prime1." $return = Get-ASNLength $Bytes $offset Write-Debug "Prime1 length is $($return.PayloadLength) bytes." $Prime1 = $Bytes[($offset + $return.FullLength - $return.PayLoadLength)..($offset + $return.FullLength - 1)] $Prime1 = Get-NormalizedArray $Prime1 $offset += $return.FullLength Write-Debug "New offset is: $offset" # prime2 Write-Debug "Process Prime2." $return = Get-ASNLength $Bytes $offset Write-Debug "Prime2 length is $($return.PayloadLength) bytes." $Prime2 = $Bytes[($offset + $return.FullLength - $return.PayLoadLength)..($offset + $return.FullLength - 1)] $Prime2 = Get-NormalizedArray $Prime2 $offset += $return.FullLength Write-Debug "New offset is: $offset" # exponent1 Write-Debug "Process Exponent1." $return = Get-ASNLength $Bytes $offset Write-Debug "Exponent1 length is $($return.PayloadLength) bytes." $Exponent1 = $Bytes[($offset + $return.FullLength - $return.PayLoadLength)..($offset + $return.FullLength - 1)] $Exponent1 = Get-NormalizedArray $Exponent1 $offset += $return.FullLength Write-Debug "New offset is: $offset" # exponent2 Write-Debug "Process Exponent2." $return = Get-ASNLength $Bytes $offset Write-Debug "Exponent2 length is $($return.PayloadLength) bytes." $Exponent2 = $Bytes[($offset + $return.FullLength - $return.PayLoadLength)..($offset + $return.FullLength - 1)] $Exponent2 = Get-NormalizedArray $Exponent2 $offset += $return.FullLength Write-Debug "New offset is: $offset" # coefficient Write-Debug "Process Coefficient." $return = Get-ASNLength $Bytes $offset Write-Debug "Coeicient length is $($return.PayloadLength) bytes." $Coefficient = $Bytes[($offset + $return.FullLength - $return.PayLoadLength)..($offset + $return.FullLength - 1)] $Coefficient = Get-NormalizedArray $Coefficient # creating Private Key BLOB structure Write-Debug "Calculating key length." $bitLen = "{0:X4}" -f $($modulus.Length * 8) Write-Debug "Key length is $($modulus.Length * 8) bits." [byte[]]$bitLen1 = iex 0x$([int]$bitLen.Substring(0,2)) [byte[]]$bitLen2 = iex 0x$([int]$bitLen.Substring(2,2)) [Byte[]]$PrivateKey = 0x07,0x02,0x00,0x00,0x00,0x24,0x00,0x00,0x52,0x53,0x41,0x32,0x00 [Byte[]]$PrivateKey = $PrivateKey + $bitLen1 + $bitLen2 + $PublicExponent + ,0x00 + ` $modulus + $Prime1 + $Prime2 + $Exponent1 + $Exponent2 + $Coefficient + $PrivateExponent return $PrivateKey}

 

0
投票

2023 年 6 月 28 日决议,工作完成(5 年后)

JSON Web Token Libraries 上有两个出色的 Powershell 库,它们可以很好地为 Google 服务器到服务器服务创建所需的签名。只需在 Powershell 脚本中包含一个库,然后生成 JWT,如下所示;

$headerTable = [ordered]@{ 'alg' = 'RS256' 'typ' = 'JWT' } $headerjson = $headerTable | ConvertTo-Json -Compress; # Setup of Payload claims $now = (Get-Date).ToUniversalTime() $createDate = [Math]::Floor([decimal](Get-Date($now) -UFormat "%s")) $expiryDate = [Math]::Floor([decimal](Get-Date($now.AddHours(1)) -UFormat "%s")) $payloadTable = [ordered]@{ 'iss' = $jsonfile.client_email 'scope' = $Scope 'aud' = $jsonfile.token_uri 'exp' = $expiryDate 'iat' = $createDate } $payloadjson = $payloadTable | ConvertTo-Json -Compress; $headerBase64 = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($headerjson)).Split('=')[0].Replace('+', '-').Replace('/', '_') $payloadBase64 = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($payloadjson)).Split('=')[0].Replace('+', '-').Replace('/', '_') $ToBeSigned = $headerBase64 + "." + $payloadBase64; $signature = Get-SignatureRS "RS256" $rsaPrivateKey $ToBeSigned; $jwt = ($ToBeSigned + "." + $signature); $requestUri = $jsonfile.token_uri; $method = 'POST'; $grant_type = [System.Web.HttpUtility]::UrlEncode("urn:ietf:params:oauth:grant-type:jwt-bearer"); $body = ("grant_type=" + $grant_type + "&assertion=" + $jwt); try { $encodedbody = [System.Text.Encoding]::UTF8.GetBytes($body) $JWTRequest = [System.Net.WebRequest]::Create($requestUri) $JWTRequest.Method = "Post" $JWTRequest.ContentType = "application/x-www-form-urlencoded" $JWTRequest.ContentLength = $encodedbody.length $requestStream = $JWTRequest.GetRequestStream() $requestStream.Write($encodedbody, 0, $encodedbody.length) $requestStream.Close() [System.Net.WebResponse] $JWTresponse = $JWTRequest.GetResponse(); if($JWTresponse -ne $null) { $JWTstatus = ($JWTresponse.StatusCode.value__).ToString().Trim(); $JWTstatusDescription = ($JWTresponse.StatusDescription).ToString().Trim(); $JWTrstream = $JWTresponse.GetResponseStream(); [System.IO.StreamReader] $JWTsread = New-Object System.IO.StreamReader -argumentList $JWTrstream; $JWTstatusJsonContent = $JWTsread.ReadToEnd(); } } etc...

过去 12 个月这对我们很有帮助

Google Identity Platform:使用 Firebase Admin SDK 私钥在 Powershell 中使用 OAuth 2.0  - powershell - SO中文参考 (2024)
Top Articles
Latest Posts
Article information

Author: Amb. Frankie Simonis

Last Updated:

Views: 5968

Rating: 4.6 / 5 (56 voted)

Reviews: 87% of readers found this page helpful

Author information

Name: Amb. Frankie Simonis

Birthday: 1998-02-19

Address: 64841 Delmar Isle, North Wiley, OR 74073

Phone: +17844167847676

Job: Forward IT Agent

Hobby: LARPing, Kitesurfing, Sewing, Digital arts, Sand art, Gardening, Dance

Introduction: My name is Amb. Frankie Simonis, I am a hilarious, enchanting, energetic, cooperative, innocent, cute, joyous person who loves writing and wants to share my knowledge and understanding with you.