Move Google EmailSettings API python code from OAuth1 to OAuth2 service account - python

To use the new Google Directory API we created an OAuth2 "service account" (see Using OAuth 2.0 for Server to Server Applications). This is basically a PKCS #12 file. All of our Directory API scripts work fine with this service account.
We also use the EmailSettings API (Developer's Guide Email Settings API) to manage some of our Google account settings. These scripts did not move to the new API format, so we continue to use the old OAuth1 authentication method. This has, until recently, worked fine. However, it appears that Google is no longer supporting OAuth1 authentication.
So, we need to move the EmailSettings scripts from OAuth1 to our OAuth2 service account. We are using the gdata Python libraries (GitHub google/gdata-python-client) to make calls to the EmailSettings API. This is how we currently authenticate to make EmailSettings API calls:
import gdata.apps.emailsettings.service
# self is an EmailSettingsService object (gdata.apps.emailsettings.service)
self.domain = "mydomain.com"
self.source = "my application name"
token = get OAuth1 token string from a file
self.SetOAuthInputParameters(
gdata.auth.OAuthSignatureMethod.HMAC_SHA1,
consumer_key = token.oauth_input_params._consumer.key,
consumer_secret = token.oauth_input_params._consumer.secret
)
token.oauth_input_params = self._oauth_input_params
self.SetOAuthToken(token)
Using these Python gdata libraries, how do I authenticate using our OAuth2 service account, i.e., the PKCS #12 file, to use the EmailSettings API?

There's another SO question which shows you how to do this but uses the slightly newer gdata.apps.emailsettings.client methods.
If you must stay with gdata.apps.emailsettings.service then you can "hack" OAuth 2.0 onto the object with something like:
Build your OAuth 2.0 credentials object as you are already doing for your Admin SDK Directory API calls.
Build your GData client object as you are already doing in lines 1-3 of your code.
Grab the access token from your credentials object and apply it as a header to your client object:
client.additional_headers = {
'Authorization': u'Bearer %s' % credentials.access_token}
If you get a 401 response (access token expired), repeat 1 and 3 to get and apply a new access token.

Related

GCP user list using python

How I can get a list of users in account GCP using python. I can't find how I can authorize using python in account and get a list. Can anybody help me?
I am assuming that you are just getting started with Google Cloud and the Python SDKs. If you are already experienced, skip to the bottom of my answer for the actual example code.
The documentation for the Google Cloud Python SDKs can be hard to figure out. The key detail is that Google documents the APIs using automated tools. Google publishes a document that SDKs can read to automatically build APIs. This might appear strange at first, but very clever when you think about it. SDKs that automatically update themselves to support the latest API implementation.
Start with the root document: Google API Client Library for Python Docs
Near the bottom is the link for documentation:
Library reference documentation by API
For your case, listing users with IAM bindings in a project, scroll down to cloudresourcemanager. Sometimes there are multiple API versions. Usually, pick the latest version. In this case, v3.
Knowing which API to use is built from experience. As you develop more and more software in Google Cloud, the logic to the architecture becomes automatic.
Cloud Resource Manager API
The API provides multiple Instance Methods. In your case, the instance method is projects.
Cloud Resource Manager API - projects
Within projects are Instance Methods. In your case, getIamPolicy().
getIamPolicy(resource, body=None, x__xgafv=None)
Sometimes you need to review the REST API to understand parameters and returned values.
Resource Manager REST API: Method: projects.getIamPolicy
For example, to understand the response from the Python SDK API, review the response documented by the REST API which includes several examples:
Resource Manager REST API: Policy
Now that I have covered the basics of discovering how to use the documentation, let's create an example that will list the roles and IAM members.
Import the required Python libraries:
from google.oauth2 import service_account
import googleapiclient.discovery
Create a variable with your Project ID. Note: do not use Project Name.
PROJECT_ID='development-123456'
Note: In the following explanation, I use a service account. Later in this answer, I show an example using ADC (Application Default Credentials) set up by the Google Cloud CLI (gcloud).
Create a variable with the full pathname to your Google Cloud Service Account JSON Key file:
SA_FILE='/config/service-account.json'
Create a variable for the required Google Cloud IAM Scopes. Typically I use the following scope as I prefer to control permissions via IAM Roles assigned to the service account:
SCOPES=['https://www.googleapis.com/auth/cloud-platform']
Create OAuth credentials from the service account:
credentials = service_account.Credentials.from_service_account_file(
filename=SA_FILE,
scopes=SCOPES)
Now we are at the point to start using the API documentation. The following code builds the API discovery document and loads the APIs for cloudresourcemanager:
service = googleapiclient.discovery.build(
'cloudresourcemanager',
'v3',
credentials=credentials)
Now call the API which will return a JSON response details the roles and members with bindings to the project:
resource = 'projects/' + PROJECT_ID
response = service.projects().getIamPolicy(resource=resource, body={}).execute()
The following is simple code to print part of the returned JSON:
for binding in response['bindings']:
print('Role:', binding['role'])
for member in binding['members']:
print(member)
Complete example that uses ADC (Application Default Credentials):
import googleapiclient.discovery
PROJECT_ID='development-123456'
service = googleapiclient.discovery.build('cloudresourcemanager', 'v3')
resource = 'projects/' + PROJECT_ID
response = service.projects().getIamPolicy(resource=resource, body={}).execute()
for binding in response['bindings']:
print('Role:', binding['role'])
for member in binding['members']:
print(member)
Complete example using a service account:
from google.oauth2 import service_account
import googleapiclient.discovery
PROJECT_ID='development-123456'
SA_FILE='/config/service-account.json'
SCOPES=['https://www.googleapis.com/auth/cloud-platform']
credentials = service_account.Credentials.from_service_account_file(
filename=SA_FILE,
scopes=SCOPES)
service = googleapiclient.discovery.build(
'cloudresourcemanager', 'v3', credentials=credentials)
resource = 'projects/' + PROJECT_ID
response = service.projects().getIamPolicy(resource=resource, body={}).execute()
for binding in response['bindings']:
print('Role:', binding['role'])
for member in binding['members']:
print(member)

Calling onedrive methods with graph api

I've purchased MS Office and they give me a space on onedrive.
Now I want to operate with that via ms graph API in my python console application (I used python onedrivesdk before but now it is said that it is deprecated).
I have registered an application and can see it via Azure AD on portal.azure.com.
Currently I'm trying to interact with my onedrive like this:
tenant_id = 'xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx'
authority = f'https://login.microsoftonline.com/{tenant_id}'
scope = 'https://graph.microsoft.com/.default'
app = msal.ConfidentialClientApplication(self.client_id, authority=authority, client_credential=self.client_secret)
result = app.acquire_token_silent(["https://graph.microsoft.com/.default"], account=None)
if not result:
logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
result = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
authToken = result['access_token']
#### Make a call to the graph API
graphResponse = requests.get('https://graph.microsoft.com/beta/me/drive',headers={'Authorization':f'Bearer {authToken}'})
if graphResponse.status_code != 200:
print('Error code: ', graphResponse.status_code)
print(graphResponse.text)
I successfully get an access token, but when I try to call /me/drive
I get status_code = 400 with
Current authenticated context is not valid for this request. This
occurs when a request is made to an endpoint that requires user
sign-in. For example, /me requires a signed-in user. Acquire a token
on behalf of a user to make requests to these endpoints. Use the
OAuth 2.0 authorization code flow for mobile and native apps and the
OAuth 2.0 implicit flow for single-page web apps
I've add permissions for the application on the portal via "API permission -> Add permission", but I'm unable to grant admin consent (In another ms account I have full fledged azure subscription where I'm an admin) because I'm not an admin. But who is admin of this account my MS office assigned to?
According to the code you provided, you use OAuth 2.0 client credentials flow to complete Azure AD auth and get access token. The access token required by service principal. We cannot use the access token to call /me/drive endpoint. We just can use the access token to call /users/<UserObjectIdOrUserPrincipalName}>/drive endpoint. For more details, please refer to the document
So if you want to call /me/drive endpoint, I suggest you use the OAuth 2.0 authorization code flow. Regarding how to implement it in your application, please refer to the sample.

Use Google API with a token [Django & AllAuth]

I am using AllAuth on my Django app to manage user authentication. With that my users can connect their Google accounts and i get a google API token (with appropriate scopes).
I would like to use that token to access google APIs (Calendar v3 in my case) with that token, as my user already used OAuth2 to sign-in on my website, and gave me access to the calendar API.
Google only gives the full process on their website (from auth to api), is there a way to build my idea, or is it simply impossible?
i have tries drive = build('calendar', 'v3', credentials=credentials) as said here but "credentials" needs to be part of an oauth2client and not just a simple string token.
Thank you for your precious time.
Simon
I know its an older question but I finally found something that worked for me. After a successful authentication with allauth, I did this to get the client token and then build the service.
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
from allauth.socialaccount.models import SocialToken, SocialApp
...
# request is the HttpRequest object
token = SocialToken.objects.get(account__user=request.user, account__provider='google')
credentials = Credentials(
token=token.token,
refresh_token=token.token_secret,
token_uri='https://oauth2.googleapis.com/token',
client_id='client-id', # replace with yours
client_secret='client-secret') # replace with yours
service = build('calendar', 'v3', credentials=credentials)

Google cloud speech api throwing 403 when trying to use it

I'm using python with google cloud speech api I did all the steps in "How to use google speech recognition api in python?" on ubuntu and on windows as well and when I trying to run the simple script from here - "https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/speech/api/speech_rest.py"
I get the next error:
<HttpError 403 when requesting https://speech.googleapis.com/$discovery/rest?version=v1beta1 returned "Google Cloud Speech API has not been used in project google.com:cloudsdktool before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/speech.googleapis.com/overview?project=google.com:cloudsdktool then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.">
what is weird is that I don't have project by the name "cloudsdktool"
I run "gcloud init", and linked the json file that I got when I created service account key with "gcloud auth activate-service-account --key-file=jsonfile" command,
I tried in linux to create google credentials environment variable and still I get the same massage
So I found two ways to fix that problem:
1 - if using google cloud sdk and the cloud speech is in beta version you need to run 'gcloud beta init' instead of 'gcloud init' and then provide the json file
2 - if you don't want to use the cloud sdk from google you can pass the json file straight in python app
here are the methods for this:
from oauth2client.client import GoogleCredentials
GoogleCredentials.from_stream('path/to/your/json')
then you just create scope on the creds and authorizing or if using grpc(streaming) you pass it to the header just like in the example.
here are the changed script for the grpc:
def make_channel(host, port):
"""Creates an SSL channel with auth credentials from the environment."""
# In order to make an https call, use an ssl channel with defaults
ssl_channel = implementations.ssl_channel_credentials(None, None, None)
# Grab application default credentials from the environment
creds = GoogleCredentials.from_stream('path/to/your/json').create_scoped([SPEECH_SCOPE])
# Add a plugin to inject the creds into the header
auth_header = (
'Authorization',
'Bearer ' + creds.get_access_token().access_token)
auth_plugin = implementations.metadata_call_credentials(
lambda _, cb: cb([auth_header], None),
name='google_creds')
# compose the two together for both ssl and google auth
composite_channel = implementations.composite_channel_credentials(
ssl_channel, auth_plugin)
return implementations.secure_channel(host, port, composite_channel)

Authorizing a python script to access the GData API without the OAuth2 user flow

I'm writing a small python script that will retrieve a list of my Google Contacts (using the Google Contacts API) and will randomly suggest one person for me to contact (good way to automate keeping in touch with friends!)
This is just a standalone script that I plan to schedule on a cron job. The problem is that Google seems to require OAuth2 style authentication, where the user (me) has to approve the access and then the app receives an authorization token I can then use to query the user's (my) contacts.
Since I'm only accessing my own data, is there a way to "pre-authorize" myself? Ideally I'd love to be able to retrieve some authorization token and then I'd run the script and pass that token as an environment variable
AUTH_TOKEN=12345 python my_script.py
That way it doesn't require user input/interaction to authorize it one time.
The implementation you're describing invokes the full "three-legged" OAuth handshake, which requires explicit user consent. If you don't need user consent, you can instead utilize "two-legged" OAuth via a Google service account, which is tied to an application, rather than a user. Once you've granted permission to your service account to access your contacts, you can use the oauth2client ServiceAccountCredentials class to directly access GData without requiring user consent.
Here's the two-legged authentication example from the Google service account documentation:
import json
from httplib2 import Http
from oauth2client.service_account import ServiceAccountCredentials
from apiclient.discovery import build
scopes = ['https://www.googleapis.com/auth/sqlservice.admin']
credentials = ServiceAccountCredentials.from_json_keyfile_name(
'service-account.json', scopes)
sqladmin = build('sqladmin', 'v1beta3', credentials=credentials)
response = sqladmin.instances().list(project='examinable-example-123').execute()
print response

Categories