Tim Dierks
Tim Dierks

Reputation: 2251

GAE Python + Google Cloud Storage authorization problems

I'm trying to get a Google Cloud Storage + Google App Engine (Python) "Hello world" app running.

I have followed the instructions to activate Google Cloud Storage and created a bucket from within my App Engine app's console. I've written a trivial program to write a test file, but when I run it, the cloud storage library throws a 403, apparently because my App Engine app's credentials aren't being presented, aren't valid, or don't have rights to this bucket.

Here's the code:

BUCKET = '/pcj-info-testing'

class TestGCS(webapp2.RequestHandler):
  def create_file(self, filename):
    self.response.write("Creating\n");
    gcs_file = gcs.open(filename, 'w', content_type = 'text/plain');
    gcs_file.write('Testing, 1, 2, 3\n')
    gcs_file.write('At ' + datetime.now().isoformat())    
    gcs_file.close()

  def get(self):
    self.response.headers['Content-Type'] = 'text/plain'
    filename = BUCKET + "/demo-file" + str(random.randrange(10**10, 10**11-1))
    self.create_file(filename)
    self.response.write('File stat:\n')
    stat = gcs.stat(filename)
    self.response.write(repr(stat))

and here is the relevant portion of the stack trace and error:

  File "/base/data/home/apps/s~pcj-info/1.373629132682543570/gcstest.py", line 14, in create_file
    gcs_file = gcs.open(filename, 'w', content_type = 'text/plain');
  File "/base/data/home/apps/s~pcj-info/1.373629132682543570/cloudstorage/cloudstorage_api.py", line 74, in open
    return storage_api.StreamingBuffer(api, filename, content_type, options)
  File "/base/data/home/apps/s~pcj-info/1.373629132682543570/cloudstorage/storage_api.py", line 597, in __init__
    errors.check_status(status, [201], path, headers, resp_headers)
  File "/base/data/home/apps/s~pcj-info/1.373629132682543570/cloudstorage/errors.py", line 106, in check_status
    raise ForbiddenError(msg)
ForbiddenError: Expect status [201] from Google Storage. But got status 403.
Path: '/pcj-info-testing/demo-file16955619179'.
Request headers: {'x-goog-resumable': 'start', 'x-goog-api-version': '2', 'content-type': 'text/plain', 'accept-encoding': 'gzip, *'}.
Response headers: {'alternate-protocol': '443:quic', 'content-length': '146', 'via': 'HTTP/1.1 GWA', 'x-google-cache-control': 'remote-fetch', 'vary': 'Origin', 'server': 'HTTP Upload Server Built on Jan 23 2014 15:07:07 (1390518427)', 'date': 'Sat, 08 Feb 2014 16:49:56 GMT', 'content-type': 'application/xml; charset=UTF-8'}.
Extra info: None.

I've looked at the access privileges on the bucket, and they look correct (although they should have been created correctly by default, according to the documentation)—the IDs listed as mine in the Google APIs Console are the same ones in the bucket permissions, with Owner permissions.

I can see the reasons that Google might return a 403 in their Status Codes documentation, but the urlfetch library in App Engine that makes the call doesn't return these error names, as far as I can tell (I assume they are the text strings returned in the HTTP response right after the error code, but the library only gives you the integer result, I think). So I'm at a loss for what to do next.

Is there any straightforward way to capture the error being returned by the API? My troubleshooting would vary dramatically if I knew the error was AccountProblem vs. InvalidSecurity or something. It's very frustrating that the API returns error codes in a way that's not accessible to users using the recommended library on a supported cloud development platform.

If I give "All Authenticated Users" access to write, it works. So it looks like I'm authenticating as someone, but that someone isn't on the permissions list. Adding the Gmail account I'm logged in as while testing the app doesn't help. (The app requires admin login to hit all URLs.)

Upvotes: 4

Views: 859

Answers (1)

jterrace
jterrace

Reputation: 67133

You need to add the appengine service account as having write permissions.

You can find the service account email under the "Application Settings" of the appengine console, under "Service Account Name".

Upvotes: 5

Related Questions