I'm using gdata-python-client
to access the Google Domain Shared Contacts API.
In enterprise applications you may want to programmatically access users data without any manual authorization on their part.
There was a protocol called 2LO (2 legged OAuth), but seems like it was linked to OAuth1 which was deprecated: "Important: OAuth 1.0 is deprecated, and registration of new OAuth 1.0 clients is closed." is all over the Oauth1 docs.
There is a new OAuth2 based recipe for "Domain-wide Delegation of Authority":
In Google Apps domains, the domain administrator can grant to third party applications domain-wide access to its users' data — this is referred as domain-wide delegation of authority. To delegate authority this way, domain administrators can use service accounts with OAuth 2.0.
This works with google-api-python-client
but not with gdata-python-client
.
Question: Is there any way to achieve this with Python? Seems like code from the gdata client is prehistoric - is there any other GAE runtime with a modern client library supporting delegation for the data APIs?
[update]
If I sign an httplib2 connection and call the Atom endpoint at I'm able to retrieve the feed.
http = httplib2.Http()
http = credentials.authorize(http)
resp, content = http.request(
'https://www.google.com/m8/feeds/contacts/default/full', 'GET'
)
Unfortunately gdata-python-client
uses httplib instead of httplib2.
[solved]
Perhaps I'm missing some step but looks like the token is not valid until we perform a call using httplib2. I have to run the above code BEFORE running the sample given in [aeijdenberg]'s answer, otherwise I get a 401.
Here's an example of how to do domain-wide delegation in Python, in Google App Engine using gdata libraries:
Create a project (https://cloud.google.com/console#/project).
Under "APIs & Auth" enable the APIs you need to use (some gdata APIs don't appear here, if so, skip this step).
Under "APIs & Auth" -> "Credentials" create a new OAuth2 client ID of type service account. Take note of the email address and client ID, and save the private key that is downloaded to a secure location.
As a domain administrator go to the Admin Console (https://admin.google.com/AdminHome), navigate to "Security" -> "Advanced Settings" -> "Managed third party OAuth Client access".
Paste the full client ID from earlier into the "Client Name" field, and paste in the scopes you need for your API access into the scopes field.
Since we are running on Google App Engine, we need to convert the PKCS12 formatted private key to PEM format (since the PyCrypto libraries currently deployed on Google App Engine won't support PCKS12):
cat secret-privatekey.p12 | openssl pkcs12 -nodes -nocerts -passin pass:notasecret | openssl rsa > secret-privatekey.pem
Put this file in your app directory.
Download the Google API Python client from https://code.google.com/p/google-api-python-client/downloads/list, select google-api-python-client-gae-1.2.zip
.
Unzip this in your app directory:
unzip ~/Downloads/google-api-python-client-gae-1.2.zip
Download the gdata python client from https://code.google.com/p/gdata-python-client/downloads/list, select gdata-2.0.18.zip
.
Install this in your app directory:
unzip ~/Downloads/gdata-2.0.18.zip
mv gdata-2.0.18/src/* .
rm -rf gdata-2.0.18/
Make sure PyCrypto is installed locally (but not in your application directory):
sudo easy_install pycrypto
In your app.yaml
, add PyCrypto as a library:
libraries:
- name: pycrypto
version: "2.6"
Declare the following helper class:
import httplib2
class TokenFromOAuth2Creds:
def __init__(self, creds):
self.creds = creds
def modify_request(self, req):
if self.creds.access_token_expired or not self.creds.access_token:
self.creds.refresh(httplib2.Http())
self.creds.apply(req.headers)
Use the private key to create a SignedJwtAssertionCredentials
object:
from oauth2client.client import SignedJwtAssertionCredentials
credentials = SignedJwtAssertionCredentials(
"<service account email>@developer.gserviceaccount.com",
file("secret-privatekey.pem", "rb").read(),
scope=["http://www.google.com/m8/feeds/"],
prn="<user to impersonate>@your-domain.com"
)
Create a gdata client and use it:
gd_client = gdata.contacts.client.ContactsClient('your-domain.com')
gd_client.auth_token = TokenFromOAuth2Creds(credentials)
xxx = gd_client.get_contacts()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With