Reputation: 11192
I am trying to use "signed URLs" to access/upload files to Google Cloud Storage (GCS).
Followed the instructions at https://developers.google.com/storage/docs/accesscontrol#Signing-Strings
What I did:
However, I am still getting this (Status: 403 Forbidden):
<?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 Google secret key and signing method.</Message>
<StringToSign>PUT
text/plain
1384084959392
x-goog-api-version:2
x-goog-project-id:99999
/mybucket/myfile.txt</StringToSign>
</Error>
Even when I retry by signing the string based on values in "StringToSign", I still get the same error.
Read various related postings here but could not find any solution and most of it refers to x-goog-api-version:1
while i am using version 2.
What am i missing? Any help would be greatly appreciated.
Upvotes: 13
Views: 13664
Reputation: 10891
I was struggling with PUT and the signed URL (with GAE Cloud Endpoints) but here are the two things I needed to do:
For PUT you need to have your string to sign look like this:
String url_signature = sign(verb + "\n" + contentMD5 + "\n" + contentType + "\n" + expiration + "\n" + "/" + BUCKET_NAME + "/" + objectName );
As explained here: https://cloud.google.com/storage/docs/access-control/signed-urls the format is:
StringToSign = HTTP_Verb + "\n" +
Content_MD5 + "\n" +
Content_Type + "\n" +
Expiration + "\n" +
Canonicalized_Extension_Headers +
Canonicalized_Resource
Those return "\n" are important. If you have too many or not enough, you will get that error. If you are not passing a contentMD5, for example, just pass in an empty string so you get the right number of return "\n"
Upvotes: 2
Reputation: 7641
To run signed url from browser you have to set HTTP header . In https://developers.google.com/storage/docs/accesscontrol#Construct-the-String
Content_Type Optional. If you provide this value the client (browser) must provide this HTTP header set to the same value.There is a word must
So if you are providing Content_Type for sign string you must provide same Content_Type in browser http header.I was also running from the same problem when i set Content_Type in browser header i was able to download a document.
Upvotes: 1
Reputation: 1228
Though the doc says Content-Type
is optional, it actually means you must
set correct content-Type
correspond to your http request header.
In this case, your must add content-type: text/plain
in the signing string.
https://cloud.google.com/storage/docs/access-control/create-signed-urls-program
Upvotes: 5
Reputation: 11192
Finally managed to PUT files to Google Cloud Storage using signed URLs. This was done by creating a simple Java program to simulate:
Server
to sign & encode a string as signature.Uploader
as an unauthenticated user submitting the PUT request using only the signature provided by Server
. Browser is simulated using Apache's HTTP Client library.You can see the demo app here.
I do not really understand why it did not work when I submitted through Chrome's Postman extension.
Upvotes: 10
Reputation: 2855
On looking into your code, can you please try creating stringToSign by omitting following headers -
"x-goog-api-version:2\n" +
"x-goog-project-id:1234\n" +
As shown below -
String stringToSign = "PUT\n" +
"\n" +
"text/plain\n" +
"1384084959392\n" +
"/test-bucket/bob.txt";
Now try generating Sign URL.
Thanks
Upvotes: 1