I have an app in GAE (Python 2.7), and now need access to Google Drive to display a (shared) list of folders and documents.
Searching usually results in pointers to DrEdit, including App Engine and Google Drive API, which asks the same question but accepts an answer I don't agree with, as DrEdit is an example app for Google Drive, not GAE.
The files list from the Drive API is what I'd like to be able to use from GAE: https://developers.google.com/drive/v2/reference/files/list
Although Google App Engine and Google Drive are both Google products, unfortunately they are not directly linked. Google Drive APIs can be accessed by the google-api-python-client library, which you have to install.
The process can be found at Python Google Drive API Quickstart Guide, and the summarized form is as follows:
On Google's side: Allow Drive API Access for your GAE program
Activate Drive API. Click the Go to credentials button to continue...
Create your consent screen: Setup your OAuth Consent Screen as Google will throw weird errors if this has not been set up:
Click on the OAuth Consent Screen tab
Select an Email address and enter a Product name.
Get credentials:
Click on the Credentials tab
Select Add credentials and then OAuth 2.0 client ID. Choose your application type, and enter the relevant details. You can change them later!
Back on the Credentials tab, download the JSON credentials (all the way to the right in the table, the download button only appears when you hover near it). Rename it client_secret.json and place it in your root code directory. You will need this to request credentials from users.
On your side: Download the google-api-python-client library, unzip it in your code directory and run python setup.py install. This will install the library which holds many Google product's APIs.
Now you are ready to use the Drive API. You can test your access using the sample code. Read it because it's a good guide for writing your own code! If you are accessing user data, you will need to request user credentials when they log in and most probably store them. Then, to use the API, the easiest way would be to get the service object:
import httplib2
from apiclient import discovery
credentials = get_credentials() #Your function to request / access stored credentials
#Authorise access to Drive using the user's credentials
http = credentials.authorise(httplib2.Http())
#The service object is the gateway to your API functions
service = discovery.build('drive', 'v2', http=http)
#Run your requests using the service object. e.g. list first 10 files:
results = service.files().list(maxResults=10).execute()
# ... etc ... Do something with results
Above code snippet is modified from sample code.
The Reference API for Google Drive can be found here.
The same general procedure is required to link GAE to other Google product's APIs as well e.g. Calendar. All the best writing your program!
For future reference (this question is quite old, but it seems like it's still an issue), now the GCP IAM API has an endpoint to get access tokens with arbitrary scopes. I'm understanding this question as a 2-legged OAuth flow (the app has access to its own Drive files), as opposed to a 3-legged OAuth flow (the app is requesting access to the Drive API on behalf of the customer).
That endpoint is used for Service Account delegation, which is a more involved flow.
You can get the right permissions on the Service Account to generate tokens for itself with this command:
gcloud iam service-accounts add-iam-policy-binding $(gcloud config get-value project)#appspot.gserviceaccount.com --member serviceAccount:$(gcloud config get-value project)#appspot.gserviceaccount.com --role roles/iam.serviceAccountTokenCreator
Example
Once the Service Account has the right permissions, you can get a token with the right scopes by first authenticating on the CLI (this step is not required on GAE, since the default service account is already authenticated):
gcloud iam service-accounts keys create key --iam-account $(gcloud config get-value project)#appspot.gserviceaccount.com
gcloud auth activate-service-account $(gcloud config get-value project)#appspot.gserviceaccount.com --key-file key
gcloud config set account $(gcloud config get-value project)#appspot.gserviceaccount.com
Then, you can make the authenticated call to the IAM API to get a token with different scopes:
curl -H"Authorization: Bearer $(gcloud auth print-access-token)" -H'content-type:application/json' https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$(gcloud config get-value project)#appspot.gserviceaccount.com:generateAccessToken -d"{'scope':['https://www.googleapis.com/auth/drive']}"
With this token, you can directly call the Drive API for files where the default GAE service account () has access:
token=$(curl -H"Authorization: Bearer $(gcloud auth print-access-token)" -H'content-type:application/json' https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$(gcloud config get-value project)#appspot.gserviceaccount.com:generateAccessToken -d"{'scope':['https://www.googleapis.com/auth/drive']}"|jq -r .accessToken)
curl -H"Authorization: Bearer $token" https://www.googleapis.com/drive/v3/files/<FILE_ID>
To finish, remember to clean up (delete the keys for this example):
gcloud iam service-accounts keys delete $(cat key|jq -r .private_key_id) --iam-account $(cat key|jq -r .client_email) -q
gcloud auth revoke $(gcloud config get-value project)#appspot.gserviceaccount.com
rm key
To make the call to generate the access token from GAE, you can use the Google Cloud Client Libraries. For Python, you would use google.cloud.iam_credentials_v1.IAMCredentialsClient.generate_access_token.
To summarize:
Grant iam.serviceAccountTokenCreator to the GAE default service account
Grant access to that account to the specific drive file
Generate a token with the right scopes from the IAM Credentials API (projects.serviceAccounts/generateAccessToken)
Make the authenticated call to the Drive API using that token
For best results, generate the token during initialization, cache it, and re-create it every hour (1 hour is the max TTL for those generated access tokens).
Related
I created a custom tensorflow model and deployed to google cloud AI platform. To access the online prediction at (https://ml.googleapis.com/v1/projects/my-project/models/my-model/versions/my-version:predict),
I can use default auth token got with the following command:
access_token=$(gcloud auth application-default print-access-token)
or, according to: https://cloud.google.com/ml-engine/docs/python-client-library, I can create a service account key, download it, and use it to in an outh2 authentication protocol.
The problem arises when I want to access the online prediction from another API that I am deploying in Google Cloud Platform: in this case the command above doesn't work and I can't access to any file to sign my jwt for authentication. How can I create my jwt without accessing to any file?
I need a third-party to upload some files to a Google Cloud Storage bucket. What is the best (or easiest) way to give them access?
The first two methods require that the user have a valid Google Account. I am ignoring Google Identity Platform in this answer. If the user has a Gmail Account, then this means they also have a Google Account. The third method uses a Google Service Account.
Method 1: Use the Google Cloud Storage Console:
Go to Storage -> Browser.
Check the desired bucket. In the right side panel under permissions, click the Add button.
Add the user's Google Account email address. Select Storage Object Creator.
The role granted is roles/storage.objectCreator. This role grants the user permissions to create objects in the bucket but the user cannot delete or overwrite objects.
Link to Cloud Storage Roles
Method 2: Use the gsutl CLI:
gsutil iam ch user:username#example.com:ObjectCreator gs://examplebucket
Link to gcloud IAM
Command to read the current bucket IAM policy:
gsutil iam get gs://examplebucket
Method 3: Use a Google Service Account
Create a Google Service Account in the Google Cloud Console
Go to IAM & admin -> Service accounts
Click CREATE SERVICE ACCOUNT
Enter a Service account name and Service account description
Click CREATE
In the next screen Service account permissions, select a role.
Select Storage -> Storage Object Creator
Click CONTINUE
Click Create key
Check the JSON radio button for the Key type
Save the json file to your local computer.
You now have Google Service Account credentials that can be setup with gsutil, gcloud and software programs.
Setting up gcloud with Service Account Credentials
The way you grant access to your third-party Customers to upload files to a Google Cloud Storage bucket would differ from one programming language to another. In PHP, you would write something like:
$options = ['gs_bucket_name' => $my_bucket];
$upload_url = CloudStorageTools::createUploadUrl('/upload/handler', $options);
and get an upload URL as a result. You may find more detail on this solution in the "Allowing Users to Upload Files" online document.
I am trying to provide access to folders that have been created using a Rest API call using a Service account (The folders are created and the return values are proper).. but when I try to add a user delegation (using the sub in the JWT header), i keep getting a unauthorized user. I have checked the Service Account creation and everything seems right there. Any pointers?
Make sure that your request includes the Authorization header with a valid token. Try also to refresh your access token using the long-lived refresh token. If this fails, direct the user through the OAuth flow, as described in Authorizing Your App with Google Drive.
Check these links:
Google drive service account and "Unauthorized client or scope in request"
Ownership of Google Drive files and Service Account using API
I have an App Engine project which:
uses google.appengine.api.get_current_user() to handle users (and login:required)
has a URL to collect some data (which requires login)
has Google users but on a custom domain
I used to have a script to pull the data using the old https://www.google.com/accounts/ClientLogin interface, but now that interface is deprecated, I'm trying to work out what I need to do to get OAuth2 working to access my App Engine URL with a user value set.
I have worked my way through OAuth2 for devices to get myself an access key for my script (i.e. I can run it, authenticate in a web browser, then poll for the access key), as described in OAuth2 For Devices.
But I'm not sure:
what scope I should be using to request the access_token compatible with get_current_user(),
how to pass this in my request to App Engine so that it can create the the user header, and
whether I need to modify my app to use this access_token, eg adding callbacks etc
With regards to the last point, user was set by google's front end infrastructure so I’m hoping that that same infrastructure can somehow convert my OAuth access_token into a login name without me needing to update my app to do the callback part, because it should all be in appengine's infrastructure right and user is set before the request comes to my app.
I am new to Google Endpoints and Datastore. I've followed several tutorials, among which this one for example: https://github.com/GoogleCloudPlatform/endpoints-codelab-android
My question is: what is the security mechanism that is used when we deploy the Endpoints backend application to Google App Engine? How does Google App Engine know you are the owner of the project? And I have this same question both for deployment through a terminal (See Step 6 of above tutorial) and for deployment through an IDE (e.g. through Maven in Eclipse).
I imagine that somehow the terminal (or the IDE) gets your credentials from the browser, which is logged in to the GAE console but I am not sure at all this is the good explanation.
Thanks! :-)
There are several ways to authenticate when deploying to Google App Engine. The recommended method uses OAuth2 to authenticate with Google (see below for another method). OAuth2 is the method used in the tutorial you mentioned (search for oauth in the link you sent), and is activated by the setting
appcfg {
oauth2 = true
}
in the build.gradle file of that tutorial. If you prefer the command-line appcfg interface, use the flag appcfg --oauth2.
When you installed the Google Cloud SDK, you were shown a web page in which you authorized the SDK to access and modify various Google Cloud services, including App Engine. The SDK locally stores a token which indicates that it is allowed to deploy to App Engine under your username. The oauth2 = true line tells appcfg to request access to App Engine using this token.
If you like, you can view (and revoke) this authorization by navigating to Google's Account Permissions page. You should see an entry for Google Cloud SDK, and clicking on it will show you that the SDK is authorized to access App Engine. If you click on "Revoke", the locally stored token will no longer be valid and you will need to re-authorize in order to use most of the Cloud SDK functionality.
If for some reason you do not want to rely on oauth2 (for example, if for security reasons you want to enter a password every time you deploy), then you can remove the oauth2 = true line (or the --oauth2 command-line argument). This will cause appcfg to prompt for your Google username and password each time you deploy. However, this is a lot less convenient, both because appcfg will not store your password, and because it does not support 2-factor authentication. So, if your Google account uses 2-factor authentication (which is really recommended), you will need to use an App Password with this approach.