Google API Cloud identity groups().create(): what is the field customer_id? - python

I would like to create a group using the API Cloud Identity and the command groups().create().
To do so, I'v used the example provided by Google:
def create_google_group(service, customer_id, group_id, group_display_name, group_description):
group_key = {"id": group_id}
group = {
"parent": "customers/" + customer_id,
"description": group_description,
"displayName": group_display_name,
"groupKey": group_key,
# Set the label to specify creation of a Google Group.
"labels": {
"cloudidentity.googleapis.com/groups.discussion_forum": ""
}
}
try:
request = service.groups().create(body=group)
request.uri += "&initialGroupConfig=WITH_INITIAL_OWNER"
response = request.execute()
print(response)
except Exception as e:
print(e)
But I got an issue:
<HttpError 400 when requesting https://cloudidentity.googleapis.com/v1/groups?alt=json&initialGroupConfig=WITH_INITIAL_OWNER returned "Invalid resource.parent". Details: "[{'#type': 'type.googleapis.com/google.rpc.BadRequest', 'fieldViolations': [{'field': 'resource.parent', 'description': 'Invalid resource.parent'}]}]">
For the field customer_id, I tried without any success:
data from https://console.developers.google.com/
ID clients OAuth 2.0, ID_client: "XXXXXXXXXXXXXXXXX.apps.googleusercontent.com"
idem but only: "XXXXXXXXXXXXXXXXX"
project identifier: 'yyyy-yyyy-123456'
'me'
'my_email#example.com'
'my_customer'
Thank you in advance for your support to understand what is expected for the field customer_id!

You can find your customer ID through the Admin console.
https://support.google.com/a/answer/10070793?hl=en
There are several other ways to find it as well.
User Resource from AdminSDK (customerId field - docs)
Organization API for GCP customers (directoryCustomerId field - docs)

Related

Renaming Google Slides Presentation (google slides API)

I'm trying to figure out how to rename a google slides presentation (ie. the document, not an individual slide). I've gone through a good amount of the Google Slide API Request documentation, but am still struggling to find the correct request. In my example, the objective is to rename the google presentation to "hello-world".
Being that I can't locate the right fields, when i go to execute the code below I keep receiving the following error:
<HttpError 400 when requesting https://slides.googleapis.com/v1/presentations/[PRESENTATION ID]:batchUpdate?alt=json returned "Invalid JSON payload received. Unknown name "Presentation" at 'requests[0]': Cannot find field.". Details: "[{'#type': 'type.googleapis.com/google.rpc.BadRequest', 'fieldViolations': [{'field': 'requests[0]', 'description': 'Invalid JSON payload received. Unknown name "Presentation" at \'requests[0]\': Cannot find field.'}]}]">
I've tried playing around with the request as much as possible, but still can't seem to figure it out. Provided below is the code. Any help is greatly appreciated.
slides_service = build('slides', 'v1', credentials=credentials)
presentationId = '####'
body = {
"requests": [{
"Presentation": {
"properties": {
"title": {
"description": "hello-world",
"type": "string"
}
}
}
}]
}
response = slides_service.presentations().batchUpdate(presentationId=presentationId,body=body).execute()
As per Yuri mentioned, Drive API would be much more reasonable instead.
Code:
new_title = 'hello-world'
file = {'title': new_title}
response = service.files().patch(fileId=file_id,
body=file,
fields='title').execute()
Reference:
Python Sample

Google calendar api acl

I was trying to use API to make some changes on my google calendar.
I have created a project on google cloud console, enable calendar API, and got the credential ready. The OAuth scope I set is:
scopes = ['https://www.googleapis.com/auth/calendar']
flow = InstalledAppFlow.from_client_secrets_file("client_secret.json", scopes=scopes)
And I got both credentials for my account.
credentials = flow.run_console()
I wanted to use ACL to gain access to the calendar, so I tried "get" and "insert" these two functions. Codes are as follows:
rule = service.acl().get(calendarId='primary', ruleId='ruleId').execute()
print('%s: %s' % (rule['id'], rule['role']))
rule = {
'scope': {
'type': 'group',
'value': 'default',
},
'role': 'owner'
}
created_rule = service.acl().insert(calendarId='primary', body=rule).execute()
print(created_rule)
However, the results show that I have some problems with the access part.
<HttpError 400 when requesting https://www.googleapis.com/calendar/v3/calendars/primary/acl/ruleId?alt=json
returned "Invalid resource id value.">
and
<HttpError 400 when requesting https://www.googleapis.com/calendar/v3/calendars/primary/acl?alt=json
returned "Invalid scope value.">
what step have I miss or do wrong?
The first error shows up in Acl.get whenever you specify an invalid ruleId. So make sure you are providing a valid ruleId in here:
rule = service.acl().get(calendarId='primary', ruleId='valid-rule-id').execute()
If you don't know the ruleId, you can look for it by calling Acl.list.
About the second error, the problem is that you are providing a wrong request body for Acl.insert. If you want to share this calendar with a group, you should provide a valid email address of the group in scope.value. default is not a valid value. Your request body should be something like this:
rule = {
'scope': {
'type': 'group',
'value': 'group-email-address',
},
'role': 'owner'
}
You will find the group email address if you click About in the corresponding group.
I hope this is of any help.

Create custom audience using Facebook API SDK

I have an access token for Facebook Audiences but I am not able to get create a custom audience using Python-SDK
First I get information about USER id using the following link:
https://developers.facebook.com/tools/debug/accesstoken
Than I use the following URL to list Ad ID's from my account:
https://graph.facebook.com/v3.2/MY_USER_ID/adaccounts
It returns a json with a list of act's like this:
{
"data": [
{
"account_id": "xxxx",
"id": "act_xxxx"
}
] }
With this ID I try to create a new audience:
from facebook_business.adobjects.adaccount import AdAccount
from facebook_business.adobjects.customaudience import CustomAudience
from facebook_business.api import FacebookAdsApi
id = 'act_xxxx'
FacebookAdsApi.init(access_token='MY TOKEN')
fields = [
]
params = {
'name': 'My new Custom Audience',
'subtype': 'CUSTOM',
'description': 'People who purchased on my website',
'customer_file_source': 'USER_PROVIDED_ONLY',
}
print(AdAccount(id).create_custom_audience(
fields=fields,
params=params,
))
Then the code produces the following error:
Unsupported post request. Object with ID 'act_xxxx' does not exist,
cannot be loaded due to missing permissions, or does not support this
operation.
I know that this ID exists because it was returned by the previous call. Debugging the access token I can see it has the following access:
read_insights, read_audience_network_insights, publish_video,
manage_pages, pages_manage_cta, pages_manage_instant_articles,
pages_show_list, publish_pages, read_page_mailboxes, ads_management,
ads_read, business_management, pages_messaging,
pages_messaging_phone_number, pages_messaging_subscriptions,
instagram_basic, instagram_manage_comments, instagram_manage_insights,
leads_retrieval
Can anyone help me to discover the reason of this error?
Thanks!

Permission problems with Google Apps Marketplace

We created an application for Google Apps Marketplace, and we want to add a new feature - get all the domain's user defined schemas. But I didn't find out how to grant our application permission to do it. Do we have to get permission again from all our customers? Or maybe create a new Google Apps Marketplace application and ask permission for it only from the customers who need it? (not all our customers need this feature).
Here is my code, it fails in two ways:
class EmailSettingsClient:
headers = None
domain = None
def __init__(self, admin_email):
self.initCredentials(admin_email)
logging.debug("headers={}".format(self.headers))
def initCredentials(self, admin_email):
http = httplib2.Http()
credentials = SignedJwtAssertionCredentials(
SERVICE_EMAIL,
PRIVATE_KEY,
scope='https://apps-apis.google.com/a/feeds/emailsettings/2.0/ https://www.googleapis.com/auth/admin.directory.user.readonly https://www.googleapis.com/auth/admin.directory.userschema.readonly',
sub=str(admin_email) # it doesn't work with this line.
)
http = credentials.authorize(http)
service = build(serviceName='admin', version='directory_v1', http=http)
creds = credentials.to_json()
access_token = credentials.token_response['access_token']
self.headers = {
'Content-type': 'application/atom+xml',
'Authorization': 'Bearer '+access_token
}
def get_all_domain_custom_schemas(self, feed_uri):
customer_id = "..." # domain customerId
logging.debug("EmailSettingsClient::get_all_domain_custom_schemas, feed_uri = {}, customerId = {} .".format(feed_uri, customer_id))
request_url = 'https://www.googleapis.com/admin/directory/v1/customer/{}/schemas'.format(customer_id)
reply = requests.get(request_url, headers=self.headers)
# data = json.loads(reply.content)
logging.info(reply.content)
customer_id = "my_customer"
logging.debug("EmailSettingsClient::get_all_domain_custom_schemas, feed_uri = {}, customerId = {} .".format(feed_uri, customer_id))
request_url = 'https://www.googleapis.com/admin/directory/v1/customer/{}/schemas'.format(customer_id)
reply = requests.get(request_url, headers=self.headers)
# data = json.loads(reply.content)
logging.info(reply.content)
class GetAllDomainCustomSchemasHandler(RequestHandler):
def post(self):
return self.get()
def get(self):
domain_str = self.request.get('domain')
domain = Domain.get_by_key_name(domain_str)
feed_uri = self.request.get('feed_uri', "")
email_settings_client = EmailSettingsClient(domain.admin)
email_settings_client.get_all_domain_custom_schemas(feed_uri)
return
One, it throws an exception if we use the "sub" parameter from another user with the domain admin's email address. And Two, if I don't include the "sub" parameter and run the application from the domain admin's account, it returns an error message: When I tried with the domain customerId, I got this error message:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "forbidden",
"message": "Not Authorized to access this resource/api"
}
],
"code": 403,
"message": "Not Authorized to access this resource/api"
}
}
And when I tried with "my_customer", I got this error message:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "backendError",
"message": "Service unavailable. Please try again"
}
],
"code": 503,
"message": "Service unavailable. Please try again"
}
}
I'm sure I missed something, but I didn't find out how to make it work. Any suggestions?
Eventually I found out that we can add this permission in the Google Developers Console, under APIs / Google Apps Marketplace SDK / Configuration. I added https://www.googleapis.com/auth/admin.directory.userschema.readonly, and each domain admin has to approve the new permissions. If you have more information you can edit this answer or post a new answer.

How to create Google Compute Engine instance with particular service account setup on it?

When you create an instance A in Google Compute Engine, it'll get predefined, "default" service account attached to it (this basically means, that you can query google API from A, being authenticated with 'default' service account).
What I'd like to do, is to setup GCE instance with service account, that's different than a default one. This should be conceptually possible, given GCE API, but fails with exception:
{
"name": "operation-1400060483459-4f958fbc7d7b9-cd817778-b80d1cad",
"operationType": "insert",
"status": "DONE",
"user": "some_name#developer.gserviceaccount.com",
"error": {
"errors": [ {
"code": "SERVICE_ACCOUNT_ACCESS_DENIED",
"message": "The user does not have access to service account 'some_name#developer.gserviceaccount.com'"
} ] } }
Here's my code in python, which setups the instance:
discovery_service = discovery.build('compute',
config['compute_api_version'],
http=SignedJwtAssertionCredentials(
service_account_name="some_name#developer.gserviceaccount.com",
private_key=key_data,
scope='https://www.googleapis.com/auth/compute')
.authorize(httplib2.Http()))
instance = {}
# sets instance configuration details here
# ...
# ...
instance['serviceAccounts'] = [{
'email': "some_name#developer.gserviceaccount.com",
'scopes': ['https://www.googleapis.com/auth/devstorage.full_control',
'https://www.googleapis.com/auth/compute',
'https://www.googleapis.com/auth/userinfo.email', ]
}]
discovery_service.instances().insert(project=project, zone=zone, body=instance)
The weirdest part of it, is that exception says "The user does not have access to service account 'some_name#developer.gserviceaccount.com'", but the "user" it refers to is the 'some_name#developer.gserviceaccount.com' itself! Which means 'some_name#developer.gserviceaccount.com' does not have access to 'some_name#developer.gserviceaccount.com', which makes no sense.
I believe you'll need to create a new service account to use the API from a non-GCE instance. The service account you're referencing works within a GCE instance only.
To do that go to the Cloud Console > Project > APIs & Auth > Credentials.
Create new Client ID
Service Account
Download the .p12 file and load that as the private key. (See example below)
Also you'll need to create an instance from a boot disk which is typically created from one of the GCE supplied images.
Here's an example using JSON Web Tokens that worked for me. It was adapted from the docs located here: https://cloud.google.com/compute/docs/tutorials/python-guide#addinganinstance.
from apiclient import discovery
from oauth2client.file import Storage
from oauth2client.client import SignedJwtAssertionCredentials
import httplib2
import os.path
INSTANCE_NAME = 'my-instance'
API_VERSION = 'v1'
GCE_URL = 'https://www.googleapis.com/compute/%s/projects/' % (API_VERSION)
PROJECT_ID = '***'
SERVICE_ACOUNT_CLIENT_ID = '***.apps.googleusercontent.com'
SERVICE_ACCOUNT_EMAIL_ADDRESS = '***#developer.gserviceaccount.com'
GCE_SCOPE = 'https://www.googleapis.com/auth/compute'
ZONE = 'us-central1-a'
DEFAULT_SERVICE_EMAIL = 'default'
DEFAULT_SCOPES = ['https://www.googleapis.com/auth/devstorage.full_control',
'https://www.googleapis.com/auth/compute']
SOURCE_IMAGE_URL = 'projects/ubuntu-os-cloud/global/images/ubuntu-1410-utopic-v20141217'
def main():
f = file('private-key.p12', 'rb')
oauth_key_data = f.read()
f.close()
http = httplib2.Http()
oauth_storage = Storage('compute-creds.dat')
oauth_credentials = oauth_storage.get()
if oauth_credentials is None or oauth_credentials.invalid:
oauth_credentials = SignedJwtAssertionCredentials(
service_account_name=SERVICE_ACCOUNT_EMAIL_ADDRESS,
private_key=oauth_key_data,
scope=GCE_SCOPE)
oauth_storage.put(oauth_credentials)
else:
oauth_credentials.refresh(http)
http = oauth_credentials.authorize(http)
gce_service = discovery.build('compute', 'v1', http=http)
project_url = '%s%s' % (GCE_URL, PROJECT_ID)
image_url = '%s%s/global/images/%s' % (
GCE_URL, 'ubuntu-os-cloud', 'ubuntu-1410-utopic-v20141217')
machine_type_url = '%s/zones/%s/machineTypes/%s' % (
project_url, ZONE, 'n1-standard-1')
network_url = '%s/global/networks/%s' % (project_url, 'default')
instance = {
'name': INSTANCE_NAME,
'machineType': machine_type_url,
'disks': [{
'autoDelete': 'true',
'boot': 'true',
'type': 'PERSISTENT',
'initializeParams' : {
'diskName': INSTANCE_NAME,
'sourceImage': SOURCE_IMAGE_URL
}
}],
'networkInterfaces': [{
'accessConfigs': [{
'type': 'ONE_TO_ONE_NAT',
'name': 'External NAT'
}],
'network': network_url
}],
'serviceAccounts': [{
'email': DEFAULT_SERVICE_EMAIL,
'scopes': DEFAULT_SCOPES
}]
}
# Create the instance
request = gce_service.instances().insert(
project=PROJECT_ID, body=instance, zone=ZONE)
response = request.execute(http=http)
response = _blocking_call(gce_service, http, response)
print response
def _blocking_call(gce_service, auth_http, response):
"""Blocks until the operation status is done for the given operation."""
status = response['status']
while status != 'DONE' and response:
operation_id = response['name']
# Identify if this is a per-zone resource
if 'zone' in response:
zone_name = response['zone'].split('/')[-1]
request = gce_service.zoneOperations().get(
project=PROJECT_ID,
operation=operation_id,
zone=zone_name)
else:
request = gce_service.globalOperations().get(
project=PROJECT_ID, operation=operation_id)
response = request.execute(http=auth_http)
if response:
status = response['status']
return response
main()
FYI: in GCE you usually get two default service accounts:
-compute#developer.gserviceaccount.com
#cloudservices.gserviceaccount.com
Note the different Email suffix (developer.gserviceaccount.com vs. cloudservices.gserviceaccount.com). It appears that using your own service account, EVEN if it has the Owner role, does not grant you access to the <number>#cloudservices.gserviceaccount.com account, only to the 1st one (<number>-compute#developer.gserviceaccount.com).
In my case, I got the aforementioned error when trying to create an instance with my own service account while specifing that the instance will use the 2nd service account from above. Once I fixed the call to request that the instance will use the 1st account, it worked.

Categories