Google shared contact API for python - python

I would like to use python to add/update external contacts that are shared to all users in a g suite domain and I'm having issue trying to figure out how. Looking at documents in https://developers.google.com/contacts/v3, looks like the process involves Google sign-in, however in the app I'm working on I don't want user to provide creds/sign in to Google, all authorization process will be done on server side.
This is my current code I'm using to get users' contact, and I'm wondering if it is possible to do anything similar to get/add/update external contacts using service account/p12 keys:
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
credentials = ServiceAccountCredentials.from_p12_keyfile(
SERVICE_ACCOUNT_EMAIL,
P12_FILE_PATH,
KEY_SECRET,
scopes=[
'https://www.googleapis.com/auth/admin.directory.user'
]
)
credentials = credentials.create_delegated(SUPER_ADMIN_EMAIL)
admin = build('admin', 'directory_v1', credentials=credentials)
admin.users().get(userKey=user_email).execute()
Thanks

Related

Consuming API Workspace for Developers

I'm trying to consume Google's Workspace APIs, but I'm having extreme difficulty with the documentation to create my first code, following the first steps I did the following
I created a project within Google Cloud
I enabled the Admin SDK API
I created a service account
I created a key in Json format
in the Workspace dashboard under delegation across domain I added the unique id and the following scope
[
'https://www.googleapis.com/auth/apps.order',
'https://www.googleapis.com/auth/siteverification',
'https://www.googleapis.com/auth/directory.readonly',
'https://www.googleapis.com/auth/admin.directory.user',
'https://www.googleapis.com/auth/admin.reports.usage.readonly',
'https://www.googleapis.com/auth/admin.reports.audit.readonly',
'https://www.googleapis.com/auth/gmail.send'
]
I would like to use the document from the link https://developers.google.com/admin-sdk/reports/reference/rest to consult the activities of a specific user but I can't find an example code to consume this API using these credentials in Python , I'm new in this area and would like some help.
Generate a token and when I tried to use an api it didn't work and it was unauthorized, below is the code I used
import requests
url = "https://admin.googleapis.com/admin/reports/v1/activity/users/usuario#exemplo.com/applications/calendar"
payload = ""
headers = {"Authorization": "Bearer xptoz_exemple_test=PHQbcdddx3xxxxxxxxxxxxddddddddd"}
response = requests.request("GET", url, data=payload, headers=headers)
print(response.text)
You are getting unauthorized because the service account doesn't have permission to do what ever it is you are trying to do. To get permission you need to be using the proper scope, and the service account needs to not only have permission to use this scope but it must have delegated to a user on the domain that has access to the data.
First you need to be sure that your authorization code is delegating to a user on your domain.
#!/usr/bin/python
from oauth2client.service_account import ServiceAccountCredentials
from httplib2 import Http
from apiclient.discovery import build
scopes = [ 'https://www.googleapis.com/auth/admin.reports.usage.readonly' ]
credentials = ServiceAccountCredentials.from_json_keyfile_name('/path/to/my/key.json', scopes)
delegated_credentials = credentials.create_delegated('me#mydomain.com')
http_auth = credentials.authorize(Http())
service = build('admin', 'directory_v1', credentials=creds)
Then you should consider having a look at Python quickstart the auth in this is set up to use an installed app. However the rest of the code should show you how to use the Client library rather then sending all the requests manually like you are now.

Google Calendar API for a simple script

I'm trying to get a simple script (python) to work against the google calendar API and don't seem to be able to get the authentication to work properly. Its for a basic raspberry pi based thing I'm trying to make at home, and I need to just grab all the events from my google calendar.
I started with the code examples on the website, but because my script is totally server side, There was no way I could get the auth challenge step to work properly (it tried with lynx, but didn't work)
I then found examples with a service account - which seemed like the right thing as it didn't need the challenge flow. Furthermore, getting the creds_with_subject, seemed like the right approach to actually get a token related to the google account that owns the calendar. I think I got it all strung together, but then I don't actually get anything listed (as a start, I was using the calendar.list() endpoint to list the calendars out). The authentication step seemed to work (no errors) - but the ensuing list was empty. I'm guessing because my service account token wasn't associated/allowed to access my google account calendar. I've enabled the calendar API in the project to which the service account belongs.
Many of the guides I found seem to mention GSuite, which its not clear if I need
So summary questions:
For this type of usage - is the service account the right approach?
If so, do I need to associate this service account with my google account (that actually owns the calendar)?
It looks like the simple API key work doesn't work any more, but thought I'd check in case there is a simpler way?
do I need GSuite?
from __future__ import print_function
import datetime
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google.oauth2 import service_account
SCOPES = ['https://www.googleapis.com/auth/calendar']
def main():
"""Shows basic usage of the Google Calendar API.
Prints the start and name of the next 10 events on the user's calendar.
"""
creds = service_account.Credentials.from_service_account_file("credentials.json", scopes=SCOPES);
creds_with_subjects = creds.with_subject("<my real account>#gmail.com");
print(creds);
print(creds_with_subjects);
service = build('calendar', 'v3', credentials=creds_with_subjects)
print(creds);
print("Getting Calendar list");
page_token = None
while True:
calendar_list = service.calendarList().list(pageToken=page_token).execute()
print(calendar_list);
page_token = calendar_list.get('nextPageToken')
if not page_token:
break
if __name__ == '__main__':
main()
Creating a service account is not enough. You also have to perform domain wide delegation and impersonate your user.
The main purpose of granting domain-wide authority to a service account is for these accounts to be able to access data on behalf of a user in your domain as otherwise the service account acts like just another account and it is trying to access its own data from Calendar, hence the empty response you are receiving.
To impersonate your user, you will have to follow the steps below:
Create a Credentials object from the service account's credentials and the scopes your application needs access to:
from google.oauth2 import service_account
SCOPES = ['SCOPE1', 'SCOPE2', ...]
SERVICE_ACCOUNT_FILE = '/path/to/service.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
Delegate domain-wide authority:
delegated_credentials = credentials.with_subject('YOURADDRESS#DOMAIN.COM')
However, in order to do this, you need to have a Google Workspace domain.
Reference
Using OAuth 2.0 for Server to Server Applications;
Authorizing Requests to the Google Calendar API.

Using Google Admin to view Drive files Domain-wide

I'm trying to list all Google Drive files Domain-wide, both users that still work here, and those that have moved on. With that, we can grep the output for certain terms (former customers) to delete customer-related files.
I believe I have a successful way to list all users using the Admin SDK Quickstart, since we have only about 200 total users (max is 500). I also have a way to list all files for a user using the Drive REST API's files.list() method. What I need to know is how to impersonate each user iteratively, in order to run the file listing script.
I have found the blurb .setServiceAccountUser(someone#domain.com) but I'm not really sure where to implement this, either in the service account authorization step, or in a separate middle-man script.
Have a look at https://github.com/pinoyyid/googleDriveTransferOwnership/blob/master/src/couk/cleverthinking/tof/Main.java
Specifically lines 285-299 which deal with generating a credential for an impersonated user.
GoogleCredential.Builder builder = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(serviceAccountEmailAddress)
.setServiceAccountPrivateKeyFromP12File(f)
.setServiceAccountScopes(Collections.singleton(SCOPE));
// if requested, impresonate a domain user
if (!"ServiceAccount".equals(impersonatedAccountEmailAddress)) {
builder.setServiceAccountUser(impersonatedAccountEmailAddress);
}
// build the Drive service
Drive service = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, null)
.setApplicationName("TOF")
.setHttpRequestInitializer(builder.build()).build();
This is Java, but should at least tell you what the steps are.
You need to implement the authorization flow for Service Accounts.
Once you create a service account in a GCP project (console.developers.google.com), enable DWD (domain-wide delegation), then authorize that service account in your G Suite admin console, that key can then be used to "impersonate" any account in the G Suite instance:
Create the credentials object from the json file
from oauth2client.service_account import ServiceAccountCredentials
scopes = ['https://www.googleapis.com/auth/gmail.readonly']
credentials = ServiceAccountCredentials.from_json_keyfile_name(
'/path/to/keyfile.json', scopes=scopes)
Create a credential that can impersonate user#example.org (could be any user in the domain though)
delegated_credentials = credentials.create_delegated('user#example.org')
Authorize the credential object (i.e. get an access_token)
from httplib2 import Http
http_auth = credentials.authorize(Http())
Call the Gmail API:
from apiclient import discovery
service = discovery.build('gmail', 'v1', http=http)
response = service.users().messages().list(userId='user#example.org').execute()

Service Accounts, web OAuth and the Directory API

I'm having issues with the Directory API + Service Accounts (Google APIs). This is my current setup:
A web page has an OAuth2 login link like this: https://accounts.google.com/o/oauth2/auth?access_type=offline&state=%2Fprofile&redirect_uri=##REDIR##&response_type=code&client_id=##CLIENTID##&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fadmin.directory.user.readonly
Users log in there, authorizing the app to access the Directory API in read-only mode on their behalf.
I then try to retrieve the users of the domain of a given user (by knowing its email address), using the Directory API.
Python code:
from apiclient.discovery import build
from oauth2client.client import SignedJwtAssertionCredentials
import httplib2
CLIENT_ID = "xzxzxzxzxzxz.apps.googleusercontent.com"
APP_EMAIL = "xzxzxzxzxzxz#developer.gserviceaccount.com"
SCOPES = ('https://www.googleapis.com/auth/admin.directory.user.readonly')
f = file('key.p12', 'rb')
key = f.read()
f.close()
credentials = SignedJwtAssertionCredentials(APP_EMAIL, key, SCOPES, sub="user#example.com")
http = httplib2.Http()
http = credentials.authorize(http)
directory_service = build('admin', 'directory_v1', http=http)
users = directory_service.users().list(domain="example.com").execute()
print users
I have also tried setting sub="user#example.com" to the app owner like this sub="appowner#company.com", to no avail.
Another thing I have tried is not using impersonation at all (ie. removing the sub=xx part), which leads me to this error:
apiclient.errors.HttpError: https://www.googleapis.com/admin/directory/v1/users?domain=example.com&alt=json returned "Not Authorized to access this resource/api">
Using impersonation always yields me this. I have verified it has to do with the scopes and the api which I try to call:
oauth2client.client.AccessTokenRefreshError: access_denied
Now, the actual questions:
Should I be using service accounts? For me, it is the most convenient way as I don't have to be storing tokens which can be outdated altogether.
If service accounts are the way to go, what am I doing wrong in the way I use them? Impersonation with either the Google Apps administrator account (which logs in via OAuth web) or the app owner account does not seem to work.

Access Google Affiliate Network product feed via the Google Search API for Shopping

I would like to access my Google Affiliate Network product feed via the Google search API for shopping. I would like to do this from a backend Python library i'm developing. Has anyone done something like this?
I have the following:
A Google account
Enabled Search API for Shopping in the Google API Console and got
an API key (for server apps) and a client ID + client secret (for installed applications).
A GAN account and got the pid.
Several advertiser who approved me so i have products available in my product feed.
OAuth2 Python Code:
from apiclient.discovery import build
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.tools import run
from oauth2client.django_orm import Storage
from models import CredentialsModel
storage = Storage(CredentialsModel, 'name', 'GAN Reporting', 'credentials')
credentials = storage.get()
if credentials is None or credentials.invalid == True:
flow = OAuth2WebServerFlow(
client_id=MyClientID,
client_secret=MyClientSecret,
scope='https://www.googleapis.com/auth/shoppingapi',
user_agent='cleverblocks/1.0',
access_type='offline')
credentials = run(flow, storage)
http = httplib2.Http()
credentials.authorize(http)
client = build('shopping', 'v1', http=http,
developerKey=MyAPIKey)
resource = client.products()
request = resource.list(source='gan:MyGANPid', country='US')
return request.execute()
Running this i get back the following error (HttpError 412):
no advertisers are registered for the given publisher
The user I am using to authenticate is listed on the GAN->settings->users section.
I've been hacking at this from all directions to the point where I'm now starting to think this API is broken. Has anyone managed to access GAN product feed via the Search API for Shopping?
Any help is appreciated.
Finally got the above oAuth code to work.
The missing step was in the GAN console, under Subscriptions->Product Feed, to set an FTP subscription for all your advertisers. I used dummy FTP credentials.
Without this step you will get the above error.

Categories

Resources