How to use amazonka presignURL

Viewed 243

I'm trying to get to grips with the amazonka library. I want to pre-sign a PUT request for S3. Looking at the example here, I put together the code below. It doesn't work when trying to send up a JPEG image from the client side. AWS complains that the signature is not correct.

My client-side code works with the nodejs aws sdk, so I can only guess that I am configuring things incorrectly here.

<Error>
  <Code>
    SignatureDoesNotMatch
  </Code>
  <Message>
    The request signature we calculated does not match the signature you provided. Check your key and signing method.
  </Message>
  <CanonicalRequest>
    PUT
    /my-bucket/test.jpg
    X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-
    Credential=[MY_AWS_ACCESS_KEY]%2F20171010%2Feu-west-
    1%2Fs3%2Faws4_request&X-Amz-Date=20171010T084724Z&X-Amz-
    Expires=100000&X-Amz-SignedHeaders=expect%3Bhost
    expect:
    host:s3-eu-west-1.amazonaws.com

    expect;host
    UNSIGNED-PAYLOAD
 </CanonicalRequest>
...

Here's my code:

getS3UrlR :: Handler Value
getS3UrlR = do
  y <- getYesod
  let settings = appSettings y

  env <- newEnv $ FromKeys (AccessKey $ encodeUtf8 $ appAwsAccessKey settings) (SecretKey $ encodeUtf8 $ appAwsSecretKey settings)
  ts  <- liftIO $ getCurrentTime

  let b = BucketName $ appS3Bucket settings
      k = ObjectKey "profile-pic-test"
  url <- liftIO $ runResourceT . runAWST env . within Ireland $ presignURL ts 100000 (putObject b k (toBody ("" :: ByteString)))
  return $ toJSON $ decodeUtf8 url

How can I go about debugging this?

Note - putObject requires a RqBody argument, but I don't have one to provide (as the client is going to supply the request body). So I just supplied an empty string. Could that be a problem?

Edit - I tried signing a GET request to see if that would work. It works fine! But PUT does not. This is the changed line that works fine:

url <- liftIO $ runResourceT . runAWST env . within Ireland $ presignURL ts 100000 (getObject b k)
1 Answers

I found an issue from Feb which led me to a workround. It seems that presignURL is adding an extraneous header to the signed URL. When I rewrite the request to remove the Expect header before signing, the resulting URL works with a simple PUT.

My workaround is included in my comment on the github issue.

Related