Start a new topic
Answered

Access denied to public uploaded file

Hello 


I uploaded a file by REST API and made it public while upload (_public = true). While I can access any non public uploaded file the "public" file is not readable (accessing from console):


This XML file does not appear to have any style information associated with it. The document tree is shown below.


<Error>

  <Code>AccessDenied</Code>

  <Message>Access denied.</Message>

  <Details>

    Anonymous caller does not have storage.objects.get access to 4161a22b4be84bb5b6edf024782ddb8d/b19bac94-fc1c-aec2-ac8b-600e34642d37/GNLP94N.png.

  </Details>

</Error>


The same happens using the provided link after uploading. 


That's the key line uploading the file with the public option (PHP, cUrL):

curl_setopt ($ch, CURLOPT_POSTFIELDS, json_encode(array("_id" => "<myId>", "gameid" => "<gameId>" "_filename" => "<filenName>", "_public" => true, "name" => "filename", "mimeType" => $mimetype, "size" => "<calculatedSize>"))); 

I know this worked once (and I haven't changed the code in between). I have checked for any changed documentation regarding this but couldn't find anything.


Pranav has access to my console. Feel free to reproduce the problem by visiting my console > file storage and clicking on file "GNLP94N.png" in the column "_downloadURL".

Any other files (not public) are accessible there.


Regards




Best Answer

Hi Tayger,


One of the options for the above error is if the upload to Google Cloud Storage failed and thus the stored metadata in Kinvey points to a non-existing file in Google Cloud Storage.


Could you please confirm if the second request to Google Cloud Storage (when making a request to _uploadURL) succeeded?


Please note that unlike private files, when uploading a public file (_public: true) would return not only the _uploadURL but also _requiredHeaders that should be included in the second request to GCS:


    "_requiredHeaders": {
        "x-goog-acl": "public-read",
        "Cache-Control": "private, max-age=0, no-transform"
    }


Not including the above headers in the second request to GCS would lead to failed request/upload and thus you may end up with the described error.


Let me know if this was the case.


Regards

Martin



Answer

Hi Tayger,


One of the options for the above error is if the upload to Google Cloud Storage failed and thus the stored metadata in Kinvey points to a non-existing file in Google Cloud Storage.


Could you please confirm if the second request to Google Cloud Storage (when making a request to _uploadURL) succeeded?


Please note that unlike private files, when uploading a public file (_public: true) would return not only the _uploadURL but also _requiredHeaders that should be included in the second request to GCS:


    "_requiredHeaders": {
        "x-goog-acl": "public-read",
        "Cache-Control": "private, max-age=0, no-transform"
    }


Not including the above headers in the second request to GCS would lead to failed request/upload and thus you may end up with the described error.


Let me know if this was the case.


Regards

Martin


Hello Martin


Thank you for the appreciated help and yes, that was it! 

The additional difficulty to find the problem is the fact that the upload command does not receive any return code/status. So you don't know really whether the upload worked or not.


I remember the google cloud header was empty at the time I created the code around it. So there was not header required at that time. I have checked it now and yes, there is a google header. Thats why my public upload didn't work anymore. I just forgot about the header part.


Since that can change anytime again the header preparation should be done dynamically. From PHP/cURL perspective I post my solution here for anyone else. Since a simple JSON encode does not work here, you have to send an array:


1. Get the returned array from requesting a public file creation:

$cloud = json_decode(curl_exec ($ch), true);


2. Prepare required header

// Create required google header
$googleheader = array();
foreach($cloud['_requiredHeaders'] as $key=>$value)
{
$googleheader[] = $key . ': ' . $value;
}

3. Upload public file with prepared header

curl_setopt($ch, CURLOPT_HTTPHEADER, $googleheader );


Thanks for your help!

Regards

Login or Signup to post a comment