Creating active users via Google Directory API - python

I am the admin for my Google domain and I am trying to automate provisioning of new users. I first attempted to do so using a command line tool called GAM.
https://github.com/jay0lee/GAM
While this tool works, at least half of the users I create are flagged for unusual activity and are created as suspended. I have tried setting the flags in a variety of combinations but am getting the same result.
I also tried to use the Directory API directly by writing a python program but all new users are still being created as suspended users. Here is my program. Can anyone shed some light on this? Thank you.
from __future__ import print_function
import httplib2
import os
from apiclient import discovery
import oauth2client
from oauth2client import client
from oauth2client import tools
try:
import argparse
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
flags = None
SCOPES = 'https://www.googleapis.com/auth/admin.directory.user'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Directory API Python Quickstart'
def get_credentials():
home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
os.makedirs(credential_dir)
credential_path = os.path.join(credential_dir,
'admin-directory_v1-python-quickstart.json')
store = oauth2client.file.Storage(credential_path)
credentials = store.get()
if not credentials or credentials.invalid:
flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
flow.user_agent = APPLICATION_NAME
if flags:
credentials = tools.run_flow(flow, store, flags)
else: # Needed only for compatibility with Python 2.6
credentials = tools.run(flow, store)
print('Storing credentials to ' + credential_path)
return credentials
def create_user():
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('admin', 'directory_v1', http=http)
userinfo = {'primaryEmail': 'jane#mydomain.com',
'name': { 'givenName': 'Jane', 'familyName': 'Smith' },
'password': '34gjklre304iojlo24j2kl3kdlj',}
service.users().insert(body=userinfo).execute()
if __name__ == '__main__':
create_user()
main()

Take note of the following statement from Directory API about Creating accounts:
If the Google account has purchased mail licenses, the new user
account is automatically assigned a mailbox. This assignment may take
a few minutes to be completed and activated.
So it may take sometime. Also note from the user resources that:
A new account is automatically suspended by Google until the initial
administrator login which activates the account. After the account is
activated, the account is no longer suspended.
So after creating the new account, try logging it in to officially activate it.

This issue ended up being attributed to testing on a free trial domain. Using a trial domain, both GAM and the python program above created some suspended users and some active users. However, when I tried both methods on my paid full version google domain I was able to consistently create all active users.

Related

How to access accountUserLinks in the Google Analtyics managment api with python?

I'm looking for the library for this method
analytics.management().accountUserLinks().insert
everytime I try to run it the error is always the same, the method management() doesn't exists into the analytics library.
I've got this from the documentation so I think it should works.
I've tried to download different python libraries without success.
The Google analytics management api. Is part of the Google apis library.
Which means you can use the google-api-python-client
sudo pip install --upgrade google-api-python-client
sample
"""A simple example of how to access the Google Analytics API."""
import argparse
from googleapiclient.discovery import build
import httplib2
from oauth2client import client
from oauth2client import file
from oauth2client import tools
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/analytics.readonly', 'https://www.googleapis.com/auth/analytics.manage.users.readonly']
# Service account key file
CREDENTIALS = 'C:\YouTube\dev\credentials.json'
VIEW_ID = '78110423'
def get_service(api_name, api_version, scope, client_secrets_path):
"""Get a service that communicates to a Google API.
Args:
api_name: string The name of the api to connect to.
api_version: string The api version to connect to.
scope: A list of strings representing the auth scopes to authorize for the
connection.
client_secrets_path: string A path to a valid client secrets file.
Returns:
A service that is connected to the specified API.
"""
# Parse command-line arguments.
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[tools.argparser])
flags = parser.parse_args([])
# Set up a Flow object to be used if we need to authenticate.
flow = client.flow_from_clientsecrets(
client_secrets_path, scope=scope,
message=tools.message_if_missing(client_secrets_path))
# Prepare credentials, and authorize HTTP object with them.
# If the credentials don't exist or are invalid run through the native client
# flow. The Storage object will ensure that if successful the good
# credentials will get written back to a file.
storage = file.Storage(api_name + '.dat')
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = tools.run_flow(flow, storage, flags)
http = credentials.authorize(http=httplib2.Http())
# Build the service object.
service = build(api_name, api_version, http=http)
return service
def get_first_profile_id(service):
# Use the Analytics service object to get the first profile id.
# Get a list of all Google Analytics accounts for the authorized user.
accounts = service.management().accounts().list().execute()
if accounts.get('items'):
# Get the first Google Analytics account.
account = accounts.get('items')[0].get('id')
account_links = service.management().accountUserLinks().list(
accountId=account
).execute()
if account_links.get('items', []):
# return the first view (profile) id.
return account_links.get('items', [])
return None
def print_results(results):
print(results)
def main():
# Authenticate and construct service.
service = get_service('analytics', 'v3', SCOPES, CREDENTIALS)
profile = get_first_profile_id(service)
print_results(profile)
if __name__ == '__main__':
main()

Google Directory API Python ETL

I'm trying to build a directory sync ETL for Google Workspace, but I'm getting 403's from the code snippet.
from google.oauth2 import service_account
from googleapiclient.discovery import build
SCOPES = ['https://www.googleapis.com/auth/admin.directory.user.readonly']
SERVICE_ACCOUNT_FILE = './credentials.json' #TODO: these creds need to be passed in more safely.
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = build('admin', 'directory_v1', credentials=credentials)
results = service.users().list(domain='mydomain.com').execute()
users = results.get('users', [])
The service account has been given domain-wide delegation to the listed scope and should be able to access the API. Other similar posts have mentioned that a domain administrator must approve the request, but that doesn't make sense in the case where I need this to run multiple times a week without any administrator intervention.
Using the Users API requires the User Management Admin role (or an equivalent custom role). You can grant this role to a service account, then you won't need domain-wide delegation at all.

How to get delegated credentials objects for invoking google apis?

I am trying to fetch gsuite alerts via API. I have created a service account as per their docs and I have assigned that service account to my google cloud function.
I do not want to use environment variables or upload credentials along with source code but I want leverage default service account used by function.
from googleapiclient.discovery import build
def get_credentials():
# if one knows credentials file location(when one uploads the json credentials file or specify them in environment variable) one can easily get the credentials by specify the path.
# In case of google cloud functions atleast I couldn't find it the path as the GOOGLE_APPLICATION_CREDENTIALS is empty in python runtime
# the below code work find if one uncomments the below line
#credentials = ServiceAccountCredentials.from_json_keyfile_name(key_file_location)
credentials = < how to get default credentials object for default service account?>
delegated_credentials = credentials.create_delegated('admin#alertcenter1.bigr.name').create_scoped(SCOPES)
return delegated_credentials
def get_alerts(api_name, api_version, key_file_location=None):
delegated_credentials = get_credentials()
alertcli = build(api_name, api_version, credentials=delegated_credentials)
resp = alertcli.alerts().list(pageToken=None).execute()
print(resp)
Is there any way I can create a default credentials object. I have tried using
from google.auth import credentials but this does not contain create_delegated function and
I have also tried ServiceAccountCredentials() but this requires signer.
Here is an example to use the Gmail API with delegated credentials. The service account credentials will need "Enable G Suite Domain-wide Delegation" enabled.
from google.oauth2 import service_account
from googleapiclient.discovery import build
credentials = service_account.Credentials.from_service_account_file(
credentials_file,
scopes=['https://www.googleapis.com/auth/gmail.send'])
impersonate = 'username#example.com'
credentials = credentials.with_subject(impersonate)
service = build('gmail', 'v1', credentials=credentials)
You can use the google.auth.default function to get the default credentials and use them to make an IAM signer which can be used to create new service account credentials which has the delegated email adress as subject. I have a more detailed answer for a similar question.
There is also Google Cloud Platform Github repository with some documentation about this method.

Google Calendar API for OAuth Web Application in Python Flask

I have been all over SO and SE looking for the particular answer to this question and cannot seem to find the answer. I am building a simple web application that uses Python Flask to access Google Calendar and fill out the calendar based on conditions. My issue is with OAuth2 and getting the redirect_uris correct. Below is my code, and every time I try to run my code I get an error that the redirect URI is incorrect and the app will not go any further. The redirect uri it seems to be obsessed with is http://localhost:8080. I have tried setting adding that redirect URI to my developers console, adding that URI with a tailing '/oauth2callback' (with and without a tailing '/'). I have also tried specifying a different URI entirely, but the error keeps mentioning http://localhost:8080 and never seems to recognize any other redirect URI despite using different client_secret.json files and specifying other uri's in flow_from_client_secrets. I have also cleared my cache before running the script every time as well as running things in chrome's incognito mode. Nothing seems to help. I know it must be something simple, and if somebody could point out what it was, I would be very appreciative!
SCOPES = 'https://www.googleapis.com/auth/calendar'
CLIENT_SECRET_FILE = 'client_secret_web.json'
APPLICATION_NAME = 'Example Calendar Application'
REDIRECT_URI = 'http://placeholder.com/oauth2callback'
home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
os.makedirs(credential_dir)
redirect_uri=""
credential_path = os.path.join(credential_dir,
'calendar-python-quickstart.json')
store = Storage(credential_path)
credentials = store.get()
flow = client.flow_from_clientsecrets(self.CLIENT_SECRET_FILE,
self.SCOPES, prompt='consent', redirect_uri=self.REDIRECT_URI)
flow.user_agent = self.APPLICATION_NAME
if self.flags:
credentials = tools.run_flow(flow, store, self.flags)
else: # Needed only for compatibility with Python 2.6
credentials = tools.run(flow, store)
print('Storing credentials to ' + credential_path)
return credentials
I think you have to delete the file created at ~/.credentials/calendar-python-quickstart.json so the program ask for permissions again

Modifying Google Calendar API to accept environment variables rather than a JSON file for Heroku

I'm pushing a Django site (python 2.7) to Heroku, however I'm getting the error:
raise InvalidClientSecretsError('File not found: "%s"' % filename)
oauth2client.clientsecrets.InvalidClientSecretsError: File not found: "calendar_secret.json"
When running a cron job, and that's because my file calendar_secret.json isn't in my repo. I purposefully didn't push it so that the data isn't known for security reasons.
My question is about how to modify Google's default code found here: https://developers.google.com/google-apps/calendar/quickstart/python, specifically the get_credentials method in order to use environment variables in either JSON or in the method directly so that I don't have to upload my calendar secrets.
Here's Google's code:
def get_credentials(self):
"""Gets valid user credentials from storage.
If nothing has been stored, or if the stored credentials are invalid,
the OAuth2 flow is completed to obtain the new credentials.
Returns:
Credentials, the obtained credential.
"""
home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
os.makedirs(credential_dir)
credential_path = os.path.join(credential_dir, 'json-file.json')
store = Storage(credential_path)
credentials = store.get()
if not credentials or credentials.invalid:
flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
flow.user_agent = APPLICATION_NAME
if flags:
credentials = tools.run_flow(flow, store, flags)
else: # Needed only for compatibility with Python 2.6
credentials = tools.run(flow, store)
print('Storing credentials to ' + credential_path)
return credentials
Which works great. But I'd love to either modify this method to use environment variables in JSON.
This is another take on the question: Environment Variables in Json file, however the answer isn't something that makes sense here.
Thanks in advance!
Figured it out! All you'll have to do is replace the flow code to the following:
flow = client.OAuth2WebServerFlow(client_id=YOUR-SAVED-ENV-ID-HERE,
client_secret=YOUR-SAVED-ENV-SECRET-HERE,
scope='https://www.googleapis.com/auth/calendar',
redirect_uris='YOUR-URIS-HERE')
More information here: https://developers.google.com/api-client-library/python/guide/aaa_oauth

Categories