How to connect pydrive with an Service Account - python-3.x

Does anyone have any example or documentation how to connect a Service Account from Google Drive API with pydrive. I managed to do it with auth2 client.

Apparently this should work, but it does not:
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from oauth2client.service_account import ServiceAccountCredentials
gauth = GoogleAuth()
scope = ["https://www.googleapis.com/auth/drive"]
gauth.credentials = ServiceAccountCredentials.from_json_keyfile_name(JSON_FILE, scope)
drive = GoogleDrive(gauth)
UPDATE: error was caused by some missing permissions in google IAM.

Related

Issues when querying Google Workspace Enterprise License Manager API

I am developing a Python 3.7 app which aims to be deployed on Google App Engine. The goal of this app is to query the Google Workspace Enterprise License Manager API in order to retrieve the list of users per Google Workspace license. So to summarize, the main goal of this app is to query the method licenseAssignments.listForProduct of the API.
I already developed an app which manage GDrive file via GSuite API, using a Service Account. So for this new app, and for testing purpose, I keep using the same Service Account. Our GSuite Admin granted this Service Account with the scope
"https://www.googleapis.com/auth/apps.licensing".
I follow the reference guide so the Enterprise License Manager API is enable on my project on GCP, and the API is enabled on Google Workspace Admin console (our GSuite Admin use the Google Workspace Enterprise License Manager API via Powershell successfully).
Here is my code:
from google.oauth2 import service_account
from googleapiclient.discovery import build
CUSTOMER_ID = 'HIDDEN_FOR_SECURITY_PURPOSE'
SERVICE_ACCOUNT_FILE = "service_account_file.json"
SCOPES = "https://www.googleapis.com/auth/apps.licensing"
def get_cred():
try:
creds = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES
)
except Exception as e:
print(e)
return creds
if __name__ == "__main__":
creds = get_cred()
service = build('licensing', 'v1', credentials=creds)
try:
response = service.licenseAssignments().listForProduct(customerId='HIDDEN_FOR_SECURITY_PURPOSE', productId='Google-Apps' ).execute()
except Exception as e:
print(e)
When running this code via App Engine, or in my computer via Jupyter Notebook, I get this error:
('No access token in response.', {'id_token': 'JWT_TOKEN_HIDDEN_FOR_SECURITY_PURPOSE'})
Lib versions:
Python 3.7
google-api-python-client==1.7.11
google-auth==1.20.1
Thanks for your help!
Edit:
I deployed the following code on GAE:
from google.cloud import bigquery
from google.oauth2 import service_account
from googleapiclient.discovery import build
import requests
import json
import pandas as pd
SERVICE_ACCOUNT_FILE = "service_account_file.json"
SCOPES = ["https://www.googleapis.com/auth/apps.licensing"]
app = Flask(__name__)
def get_cred():
try:
creds = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES
)
except Exception as e:
print(e)
return e
return creds
#app.route("/")
def main():
print("## Start")
creds = get_cred()
service = build("licensing", "v1", credentials=creds)
try:
response = (
service.licenseAssignments()
.listForProduct(customerId="HIDDEN_FOR_SECURITY_PURPOSE", productId="Google-Apps")
.execute()
)
print("## Response={}".format(response))
except Exception as e:
print(e)
print("## End")
return "OK"
if __name__ == "__main__":
# This is used when running locally only. When deploying to Google App
# Engine, a webserver process such as Gunicorn will serve the app. This
# can be configured by adding an `entrypoint` to app.yaml.
app.run(host="127.0.0.1", port=8080, debug=True)
# [END gae_python37_app]
I get the error <HttpError 503 when requesting https://licensing.googleapis.com/apps/licensing/v1/product/Google-Apps/users?customerId=[HIDDEN_FOR_SECURITY_PURPOSE]&alt=json returned "Backend Error". Details: "Backend Error">.
is your service account using Domain wide delegation? and if so is it impersonating a user that has RBAC permissions to view the licenses?
Use the API explorer https://developers.google.com/admin-sdk/licensing/reference/rest/v1/licenseAssignments/listForProduct?apix_params=%7B%22productId%22%3A%22Google-Apps%22%2C%22customerId%22%3A%22XXXXXX%20PUT%20YOUR%20CUST%20ID%20HERE%22%7D&apix=true
And autenticate against the user you are trying to impersonate, and see if you get a response.
If you dont you likley need to impersonate a Super Admin user, and if your not doing impersonateion that needs to be enabled in the GCP console first, then the scope needs to be autorized on the domain, which you mentioned has happened.

Google Drive API Python Service Account Example

Is it possible to authenticate against the Google Drive API using a Google Service Account, rather than an OAuth flow ?
The Python examples for Google Drive use OAuth - Google drive Python Quick start
However I can't find any Service Account examples.
The majority of the other Google APIs I use (Translate, Cloud Vision) do use Service Account however, so I'd like to deprecate my Google Drive OAuth code for consistency.
The best service account python example that i know of is the one for Google analytics
It should be something like this.
from apiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
SCOPES = ['https://www.googleapis.com/auth/drive.readonly']
KEY_FILE_LOCATION = '<REPLACE_WITH_JSON_FILE>'
VIEW_ID = '<REPLACE_WITH_VIEW_ID>'
def initialize_drive():
"""Initializes an service object.
Returns:
An authorized service object.
"""
creds = ServiceAccountCredentials.from_json_keyfile_name(
KEY_FILE_LOCATION, SCOPES)
# Build the service object.
service = build('drive', 'v3', credentials=creds)
return service
Once you have the drive service you should be able to use the rest of the code you have from the other tutorial. Its just the auth method that is diffrent.
Just remember to create service account credentials and not Oauth credentials.
You can use Credentials oauth2 object using the following,
import json
from googleapiclient.discovery import build
from google.oauth2.service_account import Credentials
SCOPES = ['https://www.googleapis.com/auth/drive']
service_account_info = json.load(open('service_account.json'))
creds=Credentials.from_service_account_info(
service_account_info, scopes=SCOPES)
drive_service = build('drive', 'v3', credentials=creds)

Authenticate calls to Google Cloud Functions programmatically

I am trying to authenticate to Google Cloud Functions from SAP CPI to fetch some data from a database. To push data, we use pub/sub, with a service account access token, and it works perfectly. But for the functions, it needs an identity token instead of an access token. We get the previous token with a groovy script (No Jenkins). Is it possible to authenticate to the functions also with an access token? Or to get the identity token without building a whole IAP layer?
You have to call your Cloud Functions (or Cloud Run, it's the same) with a signed identity token.
So you can use a groovy script for generating a signed identity token. Here an example
import com.google.api.client.http.GenericUrl
import com.google.api.client.http.HttpRequest
import com.google.api.client.http.HttpRequestFactory
import com.google.api.client.http.HttpResponse
import com.google.api.client.http.javanet.NetHttpTransport
import com.google.auth.Credentials
import com.google.auth.http.HttpCredentialsAdapter
import com.google.auth.oauth2.IdTokenCredentials
import com.google.auth.oauth2.IdTokenProvider
import com.google.auth.oauth2.ServiceAccountCredentials
import com.google.common.base.Charsets
import com.google.common.io.CharStreams
String myUri = "YOUR_URL";
Credentials credentials = ServiceAccountCredentials
.fromStream(new FileInputStream(new File("YOUR_SERVICE_ACCOUNT_KEY_FILE"))).createScoped("https://www.googleapis.com/auth/cloud-platform");
String token = ((IdTokenProvider) credentials).idTokenWithAudience(myUri, Collections.EMPTY_LIST).getTokenValue();
System.out.println(token);
IdTokenCredentials idTokenCredentials = IdTokenCredentials.newBuilder()
.setIdTokenProvider((ServiceAccountCredentials) credentials)
.setTargetAudience(myUri).build();
HttpRequestFactory factory = new NetHttpTransport().createRequestFactory(new HttpCredentialsAdapter(idTokenCredentials));
HttpRequest request = factory.buildGetRequest(new GenericUrl(myUri));
HttpResponse httpResponse = request.execute();
System.out.println(CharStreams.toString(new InputStreamReader(httpResponse.getContent(), Charsets.UTF_8)));
Service account key file is required only if you are outside GCP. Else, the default service account is enough, but must be a service account. Your personal user account won't work
Add this dependency (here in Maven)
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>0.20.0</version>
</dependency>
Or you can use a tool that I wrote and open sourced. I also wrote a Medium article for explaining the use cases
You can only access your secured cloud function using Identity token.
1.Create a service account with roles/cloudfunctions.invoker
2.Create a cloud function that allows only authenticated requests
https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
target_audience = 'https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME'
creds = service_account.IDTokenCredentials.from_service_account_file(
'/path/to/svc.json', target_audience=target_audience)
authed_session = AuthorizedSession(creds)
# make authenticated request and print the response, status_code
resp = authed_session.get(target_audience)
print(resp.status_code)
print(resp.text)

use the same credentials.json to access google drive/google sheet api in python

I am write interface to access google api with google drive and google sheets. For each api, I follow google api like google drive to create a credentials.json and using following code for no problem. But as interface, how can I just use one credentials.json file to access multiple api?
from googleapiclient.discovery import build
from oauth2client import client, tools
flow = client.flow_from_clientsecrets('~/credentials.json', ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive'])
creds = tools.run_flow(flow, store)
service = build('drive', 'v3', http=creds.authorize(Http()))
As long as the project on google developer console has the diffrent apis enabled you can use the same file for which ever apis you want to access your just going to have to request access for each of them.
from googleapiclient.discovery import build
from oauth2client import client, tools
flow = client.flow_from_clientsecrets('~/credentials.json',
['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive'])
creds = tools.run_flow(flow, store)
serviceDrive = build('drive', 'v3', credentials=creds)
serviceSheets = build('sheets', 'v4', credentials=creds)
You then access each of your apis though their own service. The user will be prompted to authenticate for both drive, and sheets when they login.
sheet = serviceSheets.spreadsheets()
results = serviceDrive.files().list(pageSize=10, fields="nextPageToken, files(id, name)").execute()

Python & Firebase - Unable to Read Uploaded File in Storage

I'm trying to upload my file to my Firebase Storage.
Many months ago, I could add my files using my same method, now I can add but I can't see its preview and direct link.
My code is
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db
from firebase_admin import storage
cred = credentials.Certificate('C:\\Users\\Wicaledon\\PycharmProjects\\ABC\\XXXXXX.json')
# Initialize the app with a service account, granting admin privileges
firebase_admin.initialize_app(cred, {
'databaseURL': 'https://XXXXXXXXXX.firebaseio.com/',
'storageBucket': 'XXXXXXXXXX.appspot.com'
})
database_url = 'https://XXXXXXXXXX.firebaseio.com/'
bucket = storage.bucket()
blob2 = bucket.blob('my_image.jpg')
blob2.upload_from_filename('C:\\Users\\Wicaledon\\PycharmProjects\\ABC\\my_image.jpg')
I see my file now like this. I can't see its preview and link at the right side.
But I can add same file manually from my hand, and I can see its preview and link.
What is the problem? Can you solve it ?

Resources