1

I am trying to get an object from my bucket but I always get the "signature does not match" error. I got my signature generation function from AWS sample code so I am sure that this works. I also tested the upload function and it works. I am only having trouble with the get object function. I spent a huge amount of hours verifying all scenarios/answers in this post but nothing worked. So here I am seeking your help.

Am I missing something in the headers? Here is a sample canonical request that gets created:

GET
/index.html
    
host:<bucketname>.s3.amazonaws.com
x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-date:20211127T120453Z
    
host;x-amz-content-sha256;x-amz-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

EDIT1:

I tried the AWS sample code by compiling it using javac, then ran it, the get object function works fine. But when added into my Android project, it does not work. To make sure that I copy the sample code as is, I generated its jar file and included the resulting jar file in my project. Still, same issue. This is frustrating. Argg!

EDIT2: Minimal reproducible example

  1. Download the sample code from the link above
  2. Add the code into your Android project except for com.amazonaws.services.s3.sample.RunAllSamples class.
  3. Add this call in one of your activities: GetS3ObjectSample.getS3Object(<bucketName>, <regionName>, <awsAccessKey>, <awsSecretKey>);
user1506104
  • 6,554
  • 4
  • 71
  • 89
  • Can you show a [mre] of the code you're using to create a canonical request and sign it? – Anon Coward Nov 27 '21 at 19:55
  • @AnonCoward The reproducible code is in the linked sample code. I used the canonical signature creation function there as is. But let me see how I can edit the question to help everyone easily reproduce the problem. – user1506104 Nov 28 '21 at 04:37

1 Answers1

1

This is an interesting one, and basically it boils down to the Android implementation of HttpURLConnection:

com.squareup.okhttp.internal.huc.HttpURLConnectionImpl

behaving differently to the JVM provided implementation:

sun.net.www.protocol.http.HttpURLConnection

The relevant difference here, is that around line 323 the Android implementation checks both:

  • whether the doOutput flag has been set, and
  • whether the method field is "GET"

If both these are true, it "helpfully" changes the method to "POST", which means the signature, based on the canonical request which includes the request method, is no longer valid. This is why the other samples work without issue; as they are already using a request method besides "GET", it isn't changed.

In the AWS sample code, the doOutput field is set at:

com/amazonaws/services/s3/sample/util/HttpUtils.java:86

so what I would suggest going forward is to use the definition of:

com.amazonaws.services.s3.sample.GetS3ObjectSample.getS3Object(...)

as a guide to how to calculate the required Authorization header, but use your preferred sane HTTP client instead of the:

com.amazonaws.services.s3.sample.util.HttpUtils

class provided with the samples.

msbit
  • 4,152
  • 2
  • 9
  • 22
  • Hi @msbit I am facing the same issue 403 forbidden while calling the get API from android to amazon s3 using amazon s3 with v4 signer. Could you please provide some more info related to that. – Puja Jun 29 '22 at 12:43
  • 1
    @Puja if you're using the examples from https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-examples-using-sdks.html#sig-v4-examples-using-sdk-java and the issue is reproducible in the same way as the original question, then I'd suggest modifying `com/amazonaws/services/s3/sample/util/HttpUtils.java`, calling `connection.setDoOutput(true);` at line 86 only if you actually have a body to send. If you have a different issue, perhaps ask another question for someone to help you with? – msbit Jun 29 '22 at 13:09
  • @ msbit I am calling get API to download the file from amazon s3. Not passing request body. here is my request : String response = HttpUtils.invokeHttpRequest(endpointUrl, "GET", headers, null); – Puja Jun 29 '22 at 13:20
  • but signature mismatch issue facing since 2 day. don't know what I am doing wrong – Puja Jun 29 '22 at 13:21
  • @ msbit If you have any idea to solve my issue then it will be very helpful for me – Puja Jun 29 '22 at 13:23
  • @Puja yep, as I suggested in my comment above, take a look at modifying the source for `HttpUtils`. On Android, calling `setDoOutput` on a `HttpURLConnection` will change the method from `GET` to `POST` (which breaks the signature) so you don't want to have that called unless you are actually performing a `POST` request. – msbit Jun 29 '22 at 13:50