Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I log in to an arbitrary user in appengine for use with the Drive SDK?

I have an application that needs to log into a singular Drive account and perform operations on the files automatically using a cron job. Initially, I tried to use the domain administrator login to do this, however I am unable to do any testing with the domain administrator as it seems that you cannot use the test server with a domain administrator account, which makes testing my application a bit impossible!

As such, I started looking at storing arbitray oauth tokens--especially the refresh token--to log into this account automatically after the initial setup. However, all of the APIs and documentation assume that multiple individual users are logging in manually, and I cannot find functionality in the oauth APIs that allow or account for logging into anything but the currently logged in user.

How can I achieve this in a way that I can test my code on a test domain? Can I do it without writing my own oauth library and doing the oauth requests by hand? Or is there a way to get the domain administrator authorization to work on a local test server?

like image 203
Anna Avatar asked Feb 18 '23 11:02

Anna


2 Answers

You can load the credentials for a single account into your datastore using the Remote API, which can be enabled in your app.yaml file:

builtins:
- remote_api: on

By executing

remote_api_shell.py -s your_app_id.appspot.com

from the command line you'll have access to a shell which can execute in the environment of your application. Before doing this, make sure you have your application deployed (more on local development below) and make sure the source for google-api-python-client is included by pip-installing it and running enable-app-engine-project /path/to/project to add it to your App Engine project.

Once you are in the remote shell (after executing the remote command above), perform the following:

from oauth2client.appengine import CredentialsModel
from oauth2client.appengine import StorageByKeyName
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.tools import run

KEY_NAME = 'your_choice_here'
CREDENTIALS_PROPERTY_NAME = 'credentials'
SCOPE = 'https://www.googleapis.com/auth/drive'

storage = StorageByKeyName(CredentialsModel, KEY_NAME, CREDENTIALS_PROPERTY_NAME)
flow = OAuth2WebServerFlow(
    client_id=YOUR_CLIENT_ID,
    client_secret=YOUR_CLIENT_SECRET,
    scope=SCOPE)

run(flow, storage)

NOTE: If you have not deployed your application with the google-api-python-client code, this will fail, because your application won't know how to make the same imports you made on your local machine, e.g. from oauth2client.appengine import CredentialsModel.

When run is called, your web browser will open and prompt you to accept the OAuth access for the client you've specified with CLIENT_ID and CLIENT_SECRET and after successfully completing, it will save an instance of CredentialsModel in the datastore of the deployed application your_app_id.appspot.com and it will store it using the KEY_NAME your provided.

After doing this, any caller in your application -- including your cron jobs -- can access those credentials by executing

storage = StorageByKeyName(CredentialsModel, KEY_NAME, CREDENTIALS_PROPERTY_NAME)
credentials = storage.get()

Local Development:

If you'd like to test this locally, you can run your application locally via dev_appserver.py --port=PORT /path/to/project

and you can execute the same commands using the remote API shell and pointing it at your local application:

remote_api_shell.py -s localhost:PORT

Once here, you can execute the same code you did in the remote api shell and similarly an instance of CredentialsModel will be stored in the datastore of your local development server.

As above, if you don't have the correct google-api-python-client modules included, this will fail.

EDIT: This used to recommend using the Interactive Console at:

http://localhost:PORT/_ah/admin/interactive

but it was discovered that this doesn't work because socket does not work properly in the App Engine local development sandbox.

like image 51
bossylobster Avatar answered Feb 21 '23 02:02

bossylobster


This article explains how to interact with Google Drive on behalf of users of your domain by having the Domain Administrator delegate domain-wide authority to a Service Account

This other article explains how to interact with a Drive owned by your application using a Service Account.

Note that both methods use a JWT based Service Accounts and which currently need a modified version of the google-api-python-client in order to work on App Engine.

Unlike Google App Engine Service account, JWT based Service Accounts should work with the development server.

like image 27
proppy Avatar answered Feb 21 '23 01:02

proppy