I am using google-api-python-client to site-wide delegate auth for a calendar building program I am writing.
import pytz
from datetime import datetime, timedelta
import httplib2
import json
from apiclient.discovery import build
from oauth2client.client import SignedJwtAssertionCredentials
with open('privatekey.pem', 'rb') as f:
key = f.read()
with open('config.json') as f:
config = json.load(f)
service_account_name = config['account_email']
calendarId = config['calendarId']
credentials = SignedJwtAssertionCredentials(
service_account_name, key,
scope=['https://www.googleapis.com/auth/calendar',
'https://www.googleapis.com/auth/calendar.readonly'])
http = httplib2.Http()
http = credentials.authorize(http)
service = build(serviceName='calendar', version='v3', http=http)
I do not have any issue running this on my production server, however on my dev (personal laptop) it is throwing a I do not have any issue running this on my production server, however on my dev (personal laptop) is throwing an error on urlencode. From my understanding urllib.parse.urlencode is the python 3 path? Why is my dev calling this ?
File "cal.py", line 27, in <module>
service = build(serviceName='calendar', version='v3', http=http)
return wrapped(*args, **kwargs)
File "/Library/Python/2.7/site-packages/googleapiclient/discovery.py", line 196, in build
resp, content = http.request(requested_url)
File "/Library/Python/2.7/site-packages/oauth2client/util.py", line 137, in positional_wrapper
return wrapped(*args, **kwargs)
File "/Library/Python/2.7/site-packages/oauth2client/client.py", line 534, in new_request
self._refresh(request_orig)
File "/Library/Python/2.7/site-packages/oauth2client/client.py", line 748, in _refresh
self._do_refresh_request(http_request)
File "/Library/Python/2.7/site-packages/oauth2client/client.py", line 772, in _do_refresh_request
body = self._generate_refresh_request_body()
File "/Library/Python/2.7/site-packages/oauth2client/client.py", line 1381, in _generate_refresh_request_body
body = urllib.parse.urlencode({
AttributeError: 'Module_six_moves_urllib_parse' object has no attribute 'urlencode'
Thanks for you help!
Related
I'd like to ask Azure for the details of the currently signed in user programmatically within a Python program. The program might run from the command line or within Azure batch.
Is there way to do the same thing as the azure cli does with az ad signed-in-user show, but through the Azure SDK for Python?
UPDATE:
Based on Gaurav's help and pointer to the Microsoft Graph Python Client Library, I tried the following:
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient, BlobClient, ContainerClient
from msgraphcore import GraphSession
credential = DefaultAzureCredential(
exclude_shared_token_cache_credential=True,
)
account_name = "mydatalake"
container_name = "test"
service = BlobServiceClient(
account_url=f"https://{account_name}.blob.core.windows.net/",
credential=credential
)
container_client = service.get_container_client(container_name)
blob_list = container_client.list_blobs()
for i, blob in enumerate(blob_list):
print("\t" + blob.name)
if i >= 9: break
scopes = ['user.read']
graph_session = GraphSession(credential, scopes)
result = graph_session.get('/me')
print(result.json())
I successfully get back blob names from a storage account. But it fails when it gets to the GraphAPI part with this stack trace:
Traceback (most recent call last):
File "py/src/azure_whoami.py", line 58, in <module>
result = graph_session.get('/me')
File "[...snip...]/site-packages/msgraphcore/middleware/options/middleware_control.py", line 24, in wrapper
return func(*args, **kwargs)
File "[...snip...]/site-packages/msgraphcore/graph_session.py", line 41, in get
return super().get(self._graph_url(url))
File "[...snip...]/site-packages/requests/sessions.py", line 555, in get
return self.request('GET', url, **kwargs)
File "[...snip...]/site-packages/requests/sessions.py", line 542, in request
resp = self.send(prep, **send_kwargs)
File "[...snip...]/site-packages/requests/sessions.py", line 655, in send
r = adapter.send(request, **kwargs)
File "[...snip...]/site-packages/msgraphcore/middleware/middleware.py", line 26,
in send
return self._middleware.send(request, **kwargs)
File "[...snip...]/site-packages/msgraphcore/middleware/authorization.py", line 16, in send
request.headers.update({'Authorization': 'Bearer {}'.format(self._get_access_token())})
File "[...snip...]/site-packages/msgraphcore/middleware/authorization.py", line 33, in _get_access_token
return self.credential.get_token(*self.scopes)[0]
File "[...snip...]/site-packages/azure/identity/_credentials/default.py", line 138, in get_token
token = self._successful_credential.get_token(*scopes, **kwargs)
File "[...snip...]/site-packages/azure/identity/_internal/decorators.py", line 27, in wrapper
token = fn(*args, **kwargs)
File "[...snip...]/site-packages/azure/identity/_credentials/azure_cli.py", line
58, in get_token
raise error
azure.identity._exceptions.CredentialUnavailableError: Please run 'az login' to set up an account
Based on the instructions provided here, you would first need to install the appropriate SDKs (msgraphcore and azure-identity).
After that your code would be something like (again taking from the same link)
# import modules
from azure.identity import UsernamePasswordCredential, DeviceCodeCredential
from msgraphcore import GraphSession
# Configuring credentials
# Added UsernamePassword for demo purposes only, please don't use this in production.
# ugly_credential = UsernamePasswordCredential('set-clientId', 'set-username', 'set-password')
device_credential = DeviceCodeCredential(
'set-clientId')
# There are many other options for getting an access token. See the following for more information.
# https://pypi.org/project/azure-identity/
# get data
scopes = ['user.read']
graph_session = GraphSession(device_credential, scopes)
result = graph_session.get('/me')
print(result.json())
I'm trying to make a SOAP client in python using zeepSo far I've had zero luck in trying to get it to run. I keep getting the following error.
Traceback (most recent call last):
File "C:/Users/z905/PycharmProjects/Soap_Test/soap_test.py", line 14, in <module>
client = Client(wsdl=client_location, transport=transport_with_basic_auth)
File "C:\Users\z905\PycharmProjects\Soap_Test\venv\lib\site-packages\zeep\client.py", line 134, in __init__
self.wsdl = Document(wsdl, self.transport, strict=strict)
File "C:\Users\z905\PycharmProjects\Soap_Test\venv\lib\site-packages\zeep\wsdl\wsdl.py", line 81, in __init__
root_definitions = Definition(self, document, self.location)
File "C:\Users\z905\PycharmProjects\Soap_Test\venv\lib\site-packages\zeep\wsdl\wsdl.py", line 178, in __init__
self.parse_imports(doc)
File "C:\Users\z905\PycharmProjects\Soap_Test\venv\lib\site-packages\zeep\wsdl\wsdl.py", line 270, in parse_imports
document = self.wsdl._get_xml_document(location)
File "C:\Users\z905\PycharmProjects\Soap_Test\venv\lib\site-packages\zeep\wsdl\wsdl.py", line 140, in _get_xml_document
location, self.transport, self.location, strict=self.strict)
File "C:\Users\z905\PycharmProjects\Soap_Test\venv\lib\site-packages\zeep\loader.py", line 72, in load_external
content = transport.load(url)
File "C:\Users\z905\PycharmProjects\Soap_Test\venv\lib\site-packages\zeep\transports.py", line 110, in load
content = self._load_remote_data(url)
File "C:\Users\z905\PycharmProjects\Soap_Test\venv\lib\site-packages\zeep\transports.py", line 126, in _load_remote_data
response.raise_for_status()
File "C:\Users\z905\PycharmProjects\Soap_Test\venv\lib\site-packages\requests\models.py", line 935, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 403 Client Error: Forbidden (Forbidden port) for url: http://url:7104
I've tried the program with and without basic authentication.
from zeep import Client
from requests import Session
from requests.auth import HTTPBasicAuth
from zeep.transports import Transport
client_location = "file://C:/<path-to-local-file>"
loc = "<url-to-wsdl>"
session = Session()
session.auth = HTTPBasicAuth('usrname', 'pass')
transport_with_basic_auth = Transport(session=session)
client = Client(wsdl=client_location, transport=transport_with_basic_auth)
And version without Basic Auth.
from zeep import Client
from zeep.wsse.username import UsernameToken
client_location = "file://C:/<path-to-local-file>"
loc = "<url-to-wsdl>"
client = Client(wsdl=loc, wsse=UsernameToken(usr, password, use_digest=True))
I was able to solve the issue by doing the following. The issue was caused by some firewall issues and the proxy not working.
import requests
session = requests.session()
session.trust_env = False
transport = Transport(session=session)
client = Client(wsdl=client_location, wsse=UsernameToken(usr, password, use_digest=True), transport=transport)
I am trying to implement the Backend Application flow to get an access token from the Datahug API (Following instructions in https://api.datahug.com/#gettingstarted).
from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session
def get_access_token():
token_url = 'https://apps.datahug.com/identity/connect/token'
client_id = CLIENT_ID
client_secret = CLIENT_SECRET
scope = 'datahug_api'
client = BackendApplicationClient(client_id=client_id)
client.prepare_request_body(scope=[scope])
oauth = OAuth2Session(client=client)
token = oauth.fetch_token(token_url=token_url,
client_id=client_id,
client_secret=client_secret)
return token
if __name__ == '__main__':
token = get_access_token()
print(token)
When running this code I'm getting an InvalidScopeError, namely
user:dh user$ python so_test.py
Traceback (most recent call last):
File "so_test.py", line 21, in <module>
token = get_access_token()
File "so_test.py", line 17, in get_access_token
client_secret=client_secret)
File "/Users/user/anaconda3/lib/python3.5/site-packages/requests_oauthlib/oauth2_session.py", line 244, in fetch_token
self._client.parse_request_body_response(r.text, scope=self.scope)
File "/Users/user/anaconda3/lib/python3.5/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 409, in parse_request_body_response
self.token = parse_token_response(body, scope=scope)
File "/Users/user/anaconda3/lib/python3.5/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 376, in parse_token_response
validate_token_parameters(params)
File "/Users/user/anaconda3/lib/python3.5/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 383, in validate_token_parameters
raise_from_error(params.get('error'), params)
File "/Users/user/anaconda3/lib/python3.5/site-packages/oauthlib/oauth2/rfc6749/errors.py", line 325, in raise_from_error
raise cls(**kwargs)
oauthlib.oauth2.rfc6749.errors.InvalidScopeError: (invalid_scope)
It seems that the problem is in the value scope='datahug_api', but this is the value suggested in the datahug api. Any suggestions on how to solve this much appreciated.
You are missing scope in the oauth.fetch_token().
So, your variable token should be:
token = oauth.fetch_token(token_url=token_url,scope=scope,client_id=client_id,
client_secret=client_secret)
I had success adding the scope to the BackendApplicationClient as can be seen from the developer docs.
client = BackendApplicationClient(client_id=client_id, scope=scope)
oauth = OAuth2Session(client=client)
token = oauth.fetch_token(token_url=url, client_id=client_id, client_secret=client_secret)
I am trying to connect to Google Cloud Storage from a standalone python script using a service account. I am running this script from my local system. I have also activated the service account using gcloud auth and added "GOOGLE_APPLICATION_CREDENTIALS" to point to the client_secrets.json file.
The authentication does not work and fails with the following log:
Uploading object..
Traceback (most recent call last):
File "quickstart.py", line 122, in
main(args.bucket, args.filename, args.reader, args.owner)
File "quickstart.py", line 16, in main
resp = upload_object(bucket, filename, readers, owners)
File "quickstart.py", line 43, in upload_object
service = create_service()
File "quickstart.py", line 39, in create_service
return discovery.build('storage', 'v1', http=http_auth)
File "build/bdist.macosx-10.12-intel/egg/oauth2client/util.py", line 137, in positional_wrapper
File "build/bdist.macosx-10.12-intel/egg/googleapiclient/discovery.py", line 214, in build
File "build/bdist.macosx-10.12-intel/egg/googleapiclient/discovery.py", line 261, in _retrieve_discovery_doc
File "build/bdist.macosx-10.12-intel/egg/oauth2client/transport.py", line 153, in new_request
File "build/bdist.macosx-10.12-intel/egg/oauth2client/client.py", line 765, in _refresh
File "build/bdist.macosx-10.12-intel/egg/oauth2client/client.py", line 797, in _do_refresh_request
File "/Library/Python/2.7/site-packages/httplib2-0.9.2-py2.7.egg/httplib2/__init__.py", line 1609, in request
(response, content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
File "/Library/Python/2.7/site-packages/httplib2-0.9.2-py2.7.egg/httplib2/__init__.py", line 1351, in _request
(response, content) = self._conn_request(conn, request_uri, method, body, headers)
File "/Library/Python/2.7/site-packages/httplib2-0.9.2-py2.7.egg/httplib2/__init__.py", line 1272, in _conn_request
conn.connect()
File "/Library/Python/2.7/site-packages/httplib2-0.9.2-py2.7.egg/httplib2/__init__.py", line 1036, in connect
self.disable_ssl_certificate_validation, self.ca_certs)
File "/Library/Python/2.7/site-packages/httplib2-0.9.2-py2.7.egg/httplib2/__init__.py", line 80, in _ssl_wrap_socket
cert_reqs=cert_reqs, ca_certs=ca_certs)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ssl.py", line 911, in wrap_socket
ciphers=ciphers)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ssl.py", line 520, in __init__
self._context.load_verify_locations(ca_certs)
IOError: [Errno 13] Permission denied
Here is the code snipped I am trying to run to authenticate:
import oauth2client
from oauth2client.service_account import ServiceAccountCredentials
from httplib2 import Http
from googleapiclient import discovery
import argparse
import filecmp
import json
import tempfile
import logging
logging.basicConfig(filename='debug.log',level=logging.DEBUG)
def main(bucket, filename, readers=[], owners=[]):
print('Uploading object..')
resp = upload_object(bucket, filename, readers, owners)
print(json.dumps(resp, indent=2))
def create_service():
scopes = ['https://www.googleapis.com/auth/devstorage.read_write']
credentials = ServiceAccountCredentials.from_json_keyfile_name('client_secrets.json', scopes)
http_auth = credentials.authorize(Http())
return discovery.build('storage', 'v1', http=http_auth)
def upload_object(bucket, filename, readers, owners):
service = create_service()
# This is the request body as specified:
# http://g.co/cloud/storage/docs/json_api/v1/objects/insert#request
body = {
'name': filename,
}
# If specified, create the access control objects and add them to the
# request body
if readers or owners:
body['acl'] = []
for r in readers:
body['acl'].append({
'entity': 'user-%s' % r,
'role': 'READER',
'email': r
})
for o in owners:
body['acl'].append({
'entity': 'user-%s' % o,
'role': 'OWNER',
'email': o
})
# Now insert them into the specified bucket as a media insertion.
# http://g.co/dv/resources/api-libraries/documentation/storage/v1/python/latest/storage_v1.objects.html#insert
with open(filename, 'rb') as f:
req = service.objects().insert(
bucket=bucket, body=body,
# You can also just set media_body=filename, but for the sake of
# demonstration, pass in the more generic file handle, which could
# very well be a StringIO or similar.
media_body=http.MediaIoBaseUpload(f, 'application/octet-stream'))
resp = req.execute()
return resp
I tried looking at multiple examples from google developers forum as well as other blogs. All show the same code. Not sure what is going wrong here.
From the error it looks like a simple permissions problem. Did you run the program with root priviges? If not then run the file from the command line with sudo at the beginning.
Note: IDLE doesn't run it with root.
The last line of the traceback indicates that your Python script cannot access a resource on disk with the correct permissions.
IOError: [Errno 13] Permission denied
A simple fix is to run this script with sudo.
Consider the code below:
#!/usr/bin/python
import httplib2
import pprint
from apiclient.discovery import build
from apiclient.http import MediaFileUpload
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.client import OAuth2Credentials
from oauth2client import GOOGLE_AUTH_URI
from oauth2client import GOOGLE_REVOKE_URI
from oauth2client import GOOGLE_TOKEN_URI
#Refresh token
REFRESH_TOKEN = ""
# Copy your credentials from the console
CLIENT_ID = ''
CLIENT_SECRET = ''
## Check https://developers.google.com/drive/scopes for all available scopes
OAUTH_SCOPE = ['https://www.googleapis.com/auth/drive','http://localhost:5001/storage/getGDriveAuth']
## Redirect URI for installed apps
REDIRECT_URI = ''
credentials = OAuth2Credentials(None, CLIENT_ID,
CLIENT_SECRET, REFRESH_TOKEN, None,
GOOGLE_TOKEN_URI, None,
revoke_uri=GOOGLE_REVOKE_URI,
id_token=None,
token_response=None)
# Create an httplib2.Http object and authorize it with our credentials
http = httplib2.Http()
http = credentials.authorize(http)
drive_service = build('drive', 'v2', http=http) #getting error here
file = drive_service.files().list().execute()
pprint.pprint(file)
exit();
I am getting following error:
Traceback (most recent call last):
File "python-quickstart/main.py", line 64, in <module>
drive_service = apiclient.discovery.build('drive', 'v2', http=http)
File "d:\xampp\htdocs\driveTest\lib\site-packages\oauth2client\util.py", line 137, in positional_wrapper
return wrapped(*args, **kwargs)
File "d:\xampp\htdocs\driveTest\lib\site-packages\googleapiclient\discovery.py", line 196, in build
resp, content = http.request(requested_url)
File "d:\xampp\htdocs\driveTest\lib\site-packages\oauth2client\util.py", line 137, in positional_wrapper
return wrapped(*args, **kwargs)
File "d:\xampp\htdocs\driveTest\lib\site-packages\oauth2client\client.py", line 551, in new_request
redirections, connection_type)
File "d:\xampp\htdocs\driveTest\lib\site-packages\httplib2\__init__.py", line 1139, in request
headers = self._normalize_headers(headers)
File "d:\xampp\htdocs\driveTest\lib\site-packages\httplib2\__init__.py", line 1107, in _normalize_headers
return _normalize_headers(headers)
File "d:\xampp\htdocs\driveTest\lib\site-packages\httplib2\__init__.py", line 195, in _normalize_headers
return dict([ (key.lower(), NORMALIZE_SPACE.sub(value, ' ').strip()) for (key, value) in headers.items()])
File "d:\xampp\htdocs\driveTest\lib\site-packages\httplib2\__init__.py", line 195, in <listcomp>
return dict([ (key.lower(), NORMALIZE_SPACE.sub(value, ' ').strip()) for (key, value) in headers.items()])
TypeError: sequence item 0: expected str instance, bytes found
Any idea why it is happening?
This error occurs because of the difference in the way Python 2 and Python 3 handle byte strings, more details about this are available here:
https://docs.python.org/3/whatsnew/3.0.html
This issue occurs because of the way that oath2client and httplib2 handled strings as bytes - the latest version of httplib2 which is newer than the current PyPI version(as of 03/25/2015) has included a work around for this issue.
Eventually the developers might decide on a different solution to the problem, however, you can use the newer version of httplib2 to resolve this problem in your code.