How to get Access Token from Google Service Account key file? - python

I am trying to reach my automL model prediction endpoint that I have setup, I have created a service account and added the correct role to it, now I am trying to call the endpoint in Python, but I am not sure how to call it: Here is what I have tried. The key file is downloaded from google so it's good.
from google.oauth2 import service_account
project_id = 'aaa'
endpoint_id = 'bbb'
with open('./ServiceAccountKey.json') as source:
info = json.load(source)
credentials = service_account.Credentials.from_service_account_info(info)
scoped_credentials = credentials.with_scopes(
['https://www.googleapis.com/auth/cloud-platform'])
access_token = scoped_credentials.get_access_token()
endpoint = f"https://us-central1-aiplatform.googleapis.com/v1alpha1/projects/{project_id}/locations/us-central1/endpoints/{endpoint_id}:predict"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer " + access_token}
payload = {}
x = requests.post(endpoint, data = payload, header=headers)
print(x)
The error I get is this:
AttributeError: 'Credentials' object has no attribute 'get_access_token'
Permissions I have given the service account:

The best way is to use the AI Platform Python client library. Set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path to your service account file and you are good to go.
Better to not deal with access token and refresh tokens yourself if there is a ready-made library available.

Related

How can I solve ID error when sending request to Epic Fhir Sandbox

I'm trying to use the sandbox from https://fhir.epic.com/ for Backend Services.
I am following this tutorial : https://fhir.epic.com/Documentation?docId=oauth2&section=BackendOAuth2Guide :
I already register a new app, created a JWT (using SSL keys) tested the JWT on https://jwt.io/ : works fine! When I POST the JWT to the endpoint (https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token) I get an access token.
Using this access token, I can access a single patient Appointment ressource but that's it. I don't understand how to access other Resources like DiagnosticReport, Observations, etc. I added them in the scope of my App of course but still doesn't seems to work.
What am I missing here ?
This is my code where I can access the Appointment resource:
import json
from datetime import datetime, timedelta, timezone
import requests
from requests.structures import CaseInsensitiveDict
from jwt import (
JWT,
jwk_from_dict,
jwk_from_pem,
)
from jwt.utils import get_int_from_datetime
import random
import xmltodict
def main():
instance = JWT()
message = {
# Client ID for non-production
'iss': 'my_iss_here',
'sub': 'my_sub_here',
'aud': 'https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token',
'jti': f'7777-7777-7777-7777-7777{random.randint(100,1000)}',
'iat': get_int_from_datetime(datetime.now(timezone.utc)),
'exp': get_int_from_datetime(datetime.now(timezone.utc) + timedelta(minutes=2)),
}
# Load a RSA key from a PEM file.
with open('./privatekey.pem', 'rb') as fh:
signing_key = jwk_from_pem(fh.read())
compact_jws = instance.encode(message, signing_key, alg='RS384')
headers = {}
headers['Content-Type'] = 'application/x-www-form-urlencoded'
data = {
'grant_type': 'client_credentials',
'client_assertion_type': 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
'client_assertion': compact_jws
}
x = requests.post('https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token', headers=headers, data=data)
access_token = x.json()['access_token']
headers = {}
headers['Authorization'] = f'Bearer {access_token}'
x = requests.get('https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/STU3/Appointment/eWLhfjXHp4RUczv2om.1Ii2uiHcDc6rMEjO0xHBA3', headers=headers)
print(x.content)
When I change the request for one of these two (of the online tutorial), it doesn't work:
x = requests.get('https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4/Observation/erXuFYUfucBZaryVksYEcMg3', headers=headers)
I'm using the FHIR ID of Camilia Lopez (test patient). She supposed to have a Observation Ressource but I get an error :
<OperationOutcome xmlns="http://hl7.org/fhir"><issue><severity value="fatal" /><code value="not-found" /><details><coding><system value="urn:oid:1.2.840.114350.1.13.0.1.7.2.657369" /><code value="59008" /><display value="The FHIR ID provided was not found." /></coding><text value="The FHIR ID provided was not found." /></details><diagnostics value="Invalid FHIR ID provided" /><location value="/f:id" /><expression value="id" /></issue></OperationOutcome>
Neither of those appear to be valid FHIR IDs for the resources requested in the Epic on FHIR sandbox. The IDs in the tutorial are just examples. You should use the test data reference here for identifying Patient and other resources that are available to test with. You should also ensure you are including all the necessary headers in your calls.

Error 'USER_PROJECT_DENIED' when trying to list the unused service accounts in gcp

I am trying to list unused service accounts in a gcp project
Working fine when using gcloud command
gcloud recommender insights list \
--insight-type=google.iam.serviceAccount.Insight \
--location=global \
--filter=insightSubtype=SERVICE_ACCOUNT_USAGE --project
Getting an error when i am trying to list the unused service accounts using python sdk. Below is the error
import requests
import json
import re
import sys
import subprocess
import os
from googleapiclient import discovery
from oauth2client.client import GoogleCredentials
from google.oauth2 import service_account
credentials = service_account.Credentials.from_service_account_file("")
service = discovery.build('cloudresourcemanager', 'v1', credentials=credentials)
request = service.projects().list()
token1 = subprocess.Popen("gcloud auth print-access-token", stdout=subprocess.PIPE, shell = True)
token, error = token1.communicate()
token = str(token.decode("utf-8"))
token = token.rstrip("\n")
token = token.rstrip("\r")
while request is not None:
response = request.execute()
print(response)
for project in response.get('projects', []):
projectid = project['projectId']
projectname = project['name']
headers = {
'Authorization': 'Bearer ' + token,
'x-goog-user-project': projectname
}
post_url= "https://recommender.googleapis.com/v1/projects/" + projectid + "/locations/"+ "global" +"/insightTypes/google.iam.serviceAccount.Insight/insights?filter=insightSubtype=SERVICE_ACCOUNT_USAGE"
post_url_data = requests.get(post_url, headers = headers)
get_api_json = json.loads(post_url_data.text)
print(get_api_json)
I am iterating through all projects, for some projects i am getting below error, I have checked in the console, the projects exist..
Error: project not found or deleted, status; INVALID_ARGUMENT, details: [{'#type': 'type.googleapis.com/google.rpc/ErrorInfo', 'reason':'USER_PROJECT_DENIED'
Any idea what's missing here?
the error means that you have insufficient permissions on the user project or it is deleted or not found.
A User Project is for quota and billing purposes. The caller must have the IAM permission serviceusage.services.use permission on the project. The user/quota project is set with this command:
gcloud auth application-default set-quota-project
You should always use project_id in your requests unless otherwise specified in documentation.
Notice the change in your code:
for project in response.get('projects', []):
projectid = project['projectId']
projectname = project['name']
headers = {
'Authorization': 'Bearer ' + token,
'x-goog-user-project': projectid # >>> HERE <<<, use projectid instead of projectname and make sure you have the required permission/s
}
post_url= "https://recommender.googleapis.com/v1/projects/" + projectid + "/locations/"+ "global" +"/insightTypes/google.iam.serviceAccount.Insight/insights?filter=insightSubtype=SERVICE_ACCOUNT_USAGE"
post_url_data = requests.get(post_url, headers = headers)
get_api_json = json.loads(post_url_data.text)
print(get_api_json)

Power BI Rest API - AADSTS50034: The user account {EmailHidden} does not exist in the XXXXX directory

I'm trying to get an access token instead of getting this error message
AdalError: Get Token request returned http error: 400 and server response: {"error":"invalid_grant","error_description":"AADSTS50034: The user account {EmailHidden} does not exist in the XXXXX directory. To sign into this application, the account must be added to the directory.\r\nTrace ID: f18021a8-b10a-40bf-9f0a-7975b38e2300\r\nCorrelation ID: 4f61c8f5-ed06-41f1-8d7b-756dd7c09e10\r\nTimestamp: 2020-12-16 03:27:49Z","error_codes":[50034],"timestamp":"2020-12-16 03:27:49Z","trace_id":"f18021a8-b10a-40bf-9f0a-7975b38e2300","correlation_id":"4f61c8f5-ed06-41f1-8d7b-756dd7c09e10","error_uri":"https://login.windows.net/error?code=50034"}
My python code
import adal
import json
import pyodbc
import requests
AUTHORITY_URL = 'https://login.windows.net/XXXXX'
RESOURCE = 'https://analysis.windows.net/powerbi/api'
CLIENT_ID = 'XXXXX'
userid='nurdin#xxxxx.com.my'
userpassword='xxxxx'
completedtime = []
verify = []
def make_headers(access_token):
return {
'Authorization': 'Bearer {}'.format(access_token)
}
context = adal.AuthenticationContext(AUTHORITY_URL)
token = context.acquire_token_with_username_password(RESOURCE,userid,userpassword,CLIENT_ID)
access_token = token['accessToken']
print(access_token)
Your code works fine on my side, make sure your work account is under the tenant in the AUTHORITY_URL, if not, you could follow this link to create a new user without MFA-enabled.
import adal
AUTHORITY_URL = 'https://login.windows.net/<tenant-id>'
RESOURCE = 'https://analysis.windows.net/powerbi/api'
CLIENT_ID = '<client-id>'
userid='username#tenantname.onmicrosoft.com'
userpassword='xxxxxx'
context = adal.AuthenticationContext(AUTHORITY_URL)
token = context.acquire_token_with_username_password(RESOURCE,userid,userpassword,CLIENT_ID)
access_token = token['accessToken']
print(access_token)

How to turn on/off CloudSQL instances using Python3

I'm trying to use a Python script to turn on/off a CloudSQL Instance in GoogleCloud. I've finally found a way to do it, using the GoogleCloudAPI, in Shell:
### shell script
ACCESS_TOKEN="$(gcloud auth print-access-token)"
ACTIVATION_POLICY="ALWAYS/NEVER" # Use 'ALWAYS' to turn on, 'NEVER' to turn off
curl --header "Authorization: Bearer ${ACCESS_TOKEN}" --header 'Content-Type: application/json' --data '{"settings" : {"activationPolicy" : "${ACTIVATION_POLICY}"}}' -X PATCH https://www.googleapis.com/sql/v1beta4/projects/${PROJECT_ID}/instances/${INSTANCE_ID}
So, great, problem solved... except I cannot use 'gcloud auth print-access-token' on the machine I'm running the script in, so that solves nothing. I found a question from 2017 trying to generate this 'access-token' using Python as well, which apparently didn't work either.
I need to be able to generate this 'access-token' using Python itself. I've been looking around in the Google's documentation but I still haven't managed to find anything related to that, closest I found was using oauth2 and googleapiclient to get the list of instances running, but can't seem to change activation policies from there:
### python3 script
from google.oauth2 import service_account
import googleapiclient.discovery
SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin']
SERVICE_ACCOUNT_FILE = '/path/to/service.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta4', credentials=credentials)
response = sqladmin.instances().get(project=PROJECT_ID, instance=INSTANCE_ID).execute()
The documentation doesn't make it clear how to use either tool to turn off the CloudSQL instance though, or at least none that I could find do. The above code returns me a JSON file and I can see the 'activationPolicy' there, under settings. I can't find a way to 'change it' though.
Managed to follow #norbjd suggestion and find a 'patch' method, and gave 'SQL Admin' permission to my credentials, so it can now use the sqladmin API. Tried to patch it using the following code:
instance = sqladmin.instances().patch(project=PROJECT_ID, instance=INSTANCE_ID)
instance.data = {"settings" : {"activationPolicy" : "NEVER"}} #also tried with it in a string, like this: instance.data = {"settings" : {"activationPolicy" : "NEVER"}}
instance.headers['Content-Type'] = 'application/json'
instance.execute()
Considering instance.data didn't exist prior to that, but instance.headers did:
{'accept': 'application/json', 'accept-encoding': 'gzip, deflate', 'user-agent': '(gzip)', 'x-goog-api-client': 'gdcl/1.7.11 gl-python/3.6.9'}
After the execute, though, nothing seemed to happen. It did not change the actual activationPolicy.
In the end, the problem was solved using the ACCESS_TOKEN and making a Python request using the requests module. If you try to get an ACCESS_TOKEN from your credentials just after generating them, you won't be getting any, but if you actually use your credentials with the googleapiclient.discovery, this updates that object with a valid access token, that can then be used in a Python request, as follows:
from google.oauth2 import service_account
import googleapiclient.discovery
import json
import requests
PROJECT_ID = '{PROJECT_ID_HERE}'
INSTANCE_ID = '{INSTANCE_ID_HERE}'
SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin']
SERVICE_ACCOUNT_FILE = '/path/to/service.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta4', credentials=credentials)
response = sqladmin.instances().get(project=PROJECT_ID, instance=INSTANCE_ID).execute()
print(json.dumps(response))
access_token = credentials.token # Now that the credentials were used, they have a valid access_token associated with them!
activation_policy = 'NEVER' # or 'ALWAYS'
url = "https://www.googleapis.com/sql/v1beta4/projects/{PROJECT_ID}/instances/{INSTANCE_ID}".format(PROJECT_ID=PROJECT_ID, INSTANCE_ID=INSTANCE_ID)
header = {
"Authorization" : "Bearer {}".format(access_token),
"Content-Type" : "application/json"
}
data = {
"settings" : {
"activationPolicy" : activation_policy
}
}
response = requests.patch(url, headers=header, data=json.dumps(data))
print(response.text)
All it took was to actually use the credentials for something before attempting to retrieve the ACCESS_TOKEN

How to access spotify's web api with client id and secret?

I'm trying to write a script that creates a playlist on my spotify account in python, from scratch and not using a module like spotipy.
My question is how do I authenticate with my client id and client secret key using the requests module or grab an access token using those credentials?
Try this full Client Credentials Authorization flow.
First step – get an authorization token with your credentials:
CLIENT_ID = " < your client id here... > "
CLIENT_SECRET = " < your client secret here... > "
grant_type = 'client_credentials'
body_params = {'grant_type' : grant_type}
url='https://accounts.spotify.com/api/token'
response = requests.post(url, data=body_params, auth = (CLIENT_ID, CLIENT_SECRET))
token_raw = json.loads(response.text)
token = token_raw["access_token"]
Second step – make a request to any of the playlists endpoint. Make sure to set a valid value for <spotify_user>.
headers = {"Authorization": "Bearer {}".format(token)}
r = requests.get(url="https://api.spotify.com/v1/users/<spotify_user>/playlists", headers=headers)
print(r.text)
As it is referenced here, you have to give the Bearer token to the Authorization header, and using requests it is done by declaring the "headers" optional:
r = requests.post(url="https://api.spotify.com/v1/users/{your-user}/playlists",
headers={"Authorization": <token>, ...})
The details of how can you get the Bearer token of your users can be found here

Categories

Resources