question

SebastinMatasCarreira-9447 avatar image
0 Votes"
SebastinMatasCarreira-9447 asked IanXue-MSFT edited

Invoke-WebRequest overriding the Date header’s format

Hello, I’m trying to write a script that need to perform an authenticated request to AWS S3. As per AWS’s documentation, the request requires to be authenticated via a summary of the request’s method, Date header, bucket name and object key being signed with the secret key using SHA1. I created a PS function that automatically generates the date string with the same format as shown in the documentation and the resulting Authorization header with the signed content. I then tested this using PostMan and it worked as expected.

However, when I’m trying to perform this request using either Invoke-WebRequest or Invoke-RestMethod it fails, claiming that the signatures do not match. Luckily, S3’s response includes the request summary that should be signed to perform the authentication and I found that the date string is being changed from the format I sent to using the UTC time zone and replacing the time zone offset by “GMT”, here is an example of what I mean (some values were redacted for security reasons). The content being printed after the execution of Get-AWSAuthHeaders is the string that is being signed.

 >$headers = Get-AWSAuthHeaders GET
 GET
    
    
 Wed, 28 Apr 2021 18:51:53 -0300
 /[REDACTED]/clipboard
 >$headers
 Name                           Value
 ----                           -----
 Date                           Wed, 28 Apr 2021 18:51:53 -0300
 Authorization                  AWS [REDACTED]:iPvDMgLYHnHVbmnThKHJu7nbuAM=
 >try {
 >> Invoke-WebRequest -Method GET -Headers $headers -Uri https://[REDACTED].s3-sa-east-1.amazonaws.com/clipboard
 >> } catch {
 >>         $result = $_.Exception.Response.GetResponseStream()
 >>         $reader = New-Object System.IO.StreamReader($result)
 >>         $reader.BaseStream.Position = 0
 >>         $reader.DiscardBufferedData()
 >>         $responseBody = $reader.ReadToEnd();
 >> }
 >$responseBody
 <?xml version="1.0" encoding="UTF-8"?>
 <Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>[REDACTED]]</AWSAccessKeyId><StringToSign>GET
    
    
 Wed, 28 Apr 2021 21:51:53 GMT
 /[REDACTED]/clipboard</StringToSign><SignatureProvided>iPvDMgLYHnHVbmnThKHJu7nbuAM=</SignatureProvided><StringToSignBytes>[REDACTED]</StringToSignBytes><RequestId>58A6CR4XMSPC8ZCT</RequestId><HostId>fldDRoFiacucacOXVJ93mMVCOhikNKft+01fHuDPKsMz31nhSneVGb96/A23AAn8KE/NAqVV3BY=</HostId></Error>

As you can see, S3 is trying to sign a string with the date in a different format than the one I’m passing to Invoke-WebRequest and given that this does not happen when using PostMan, means that it’s PowerShell changing the header value on my side and not S3 on AWS’ side.

Here is the code for Get-AWSAuthHeaders in case that it helps (the conf object holds just configuration info for the redacted values):

 function Get-AWSAuthHeaders ($method) {
     $bucket_name = $conf.bucket_name
     $aws_access_key = $conf.aws_access_key
     $date_str = (Get-Date).ToString('ddd, d MMM yyyy HH:mm:ss -0300', [CultureInfo]'en-us')
     $hmacsha = New-Object System.Security.Cryptography.HMACSHA1
     $string_to_sign = "$method`n`n`n$date_str`n/$bucket_name/clipboard"
     Write-Host $string_to_sign
     $hmacsha.key = [Text.Encoding]::ASCII.GetBytes($conf.aws_secret_key)
     $signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($string_to_sign))
     $signed_b64 = [Convert]::ToBase64String($signature)
     return @{
         "Authorization" = "AWS $aws_access_key`:$signed_b64"
         "Date" = $date_str
     }
 }

I also tried using PostMan’s feature to export the request as code and it results in the same issue (I also tested exporting it as cURL and it works fine too but I need it using PowerShell, not cURL).



windows-server-powershell
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

IanXue-MSFT avatar image
0 Votes"
IanXue-MSFT answered IanXue-MSFT edited

Hi,

Per my test, it appears the Invoke-WebRequest cmdlet always converts the header “Date” to the universal time.

I tried to manually convert the time to a DateTime object but it still got converted to UTC.

Best Regards,
Ian Xue
============================================
If the Answer is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.