Index: third_party/oauth2client/appengine.py |
diff --git a/third_party/oauth2client/appengine.py b/third_party/oauth2client/appengine.py |
index 5cd3f4bafb4b67218494d68cf734881273a61e94..4131513d1d1a498ec527b32c8c0c07fb8547acbc 100644 |
--- a/third_party/oauth2client/appengine.py |
+++ b/third_party/oauth2client/appengine.py |
@@ -1,4 +1,4 @@ |
-# Copyright (C) 2010 Google Inc. |
+# Copyright 2014 Google Inc. All rights reserved. |
# |
# Licensed under the Apache License, Version 2.0 (the "License"); |
# you may not use this file except in compliance with the License. |
@@ -19,14 +19,14 @@ Utilities for making it easier to use OAuth 2.0 on Google App Engine. |
__author__ = 'jcgregorio@google.com (Joe Gregorio)' |
-import base64 |
import cgi |
-import httplib2 |
+import json |
import logging |
import os |
import pickle |
import threading |
-import time |
+ |
+import httplib2 |
from google.appengine.api import app_identity |
from google.appengine.api import memcache |
@@ -41,7 +41,6 @@ from oauth2client import GOOGLE_TOKEN_URI |
from oauth2client import clientsecrets |
from oauth2client import util |
from oauth2client import xsrfutil |
-from oauth2client.anyjson import simplejson |
from oauth2client.client import AccessTokenRefreshError |
from oauth2client.client import AssertionCredentials |
from oauth2client.client import Credentials |
@@ -159,15 +158,20 @@ class AppAssertionCredentials(AssertionCredentials): |
Args: |
scope: string or iterable of strings, scope(s) of the credentials being |
requested. |
+ **kwargs: optional keyword args, including: |
+ service_account_id: service account id of the application. If None or |
+ unspecified, the default service account for the app is used. |
""" |
self.scope = util.scopes_to_string(scope) |
+ self._kwargs = kwargs |
+ self.service_account_id = kwargs.get('service_account_id', None) |
# Assertion type is no longer used, but still in the parent class signature. |
super(AppAssertionCredentials, self).__init__(None) |
@classmethod |
- def from_json(cls, json): |
- data = simplejson.loads(json) |
+ def from_json(cls, json_data): |
+ data = json.loads(json_data) |
return AppAssertionCredentials(data['scope']) |
def _refresh(self, http_request): |
@@ -186,11 +190,22 @@ class AppAssertionCredentials(AssertionCredentials): |
""" |
try: |
scopes = self.scope.split() |
- (token, _) = app_identity.get_access_token(scopes) |
- except app_identity.Error, e: |
+ (token, _) = app_identity.get_access_token( |
+ scopes, service_account_id=self.service_account_id) |
+ except app_identity.Error as e: |
raise AccessTokenRefreshError(str(e)) |
self.access_token = token |
+ @property |
+ def serialization_data(self): |
+ raise NotImplementedError('Cannot serialize credentials for AppEngine.') |
+ |
+ def create_scoped_required(self): |
+ return not self.scope |
+ |
+ def create_scoped(self, scopes): |
+ return AppAssertionCredentials(scopes, **self._kwargs) |
+ |
class FlowProperty(db.Property): |
"""App Engine datastore Property for Flow. |
@@ -434,6 +449,7 @@ class StorageByKeyName(Storage): |
entity_key = db.Key.from_path(self._model.kind(), self._key_name) |
db.delete(entity_key) |
+ @db.non_transactional(allow_existing=True) |
def locked_get(self): |
"""Retrieve Credential from datastore. |
@@ -456,6 +472,7 @@ class StorageByKeyName(Storage): |
credentials.set_store(self) |
return credentials |
+ @db.non_transactional(allow_existing=True) |
def locked_put(self, credentials): |
"""Write a Credentials to the datastore. |
@@ -468,6 +485,7 @@ class StorageByKeyName(Storage): |
if self._cache: |
self._cache.set(self._key_name, credentials.to_json()) |
+ @db.non_transactional(allow_existing=True) |
def locked_delete(self): |
"""Delete Credential from datastore.""" |
@@ -553,16 +571,14 @@ class OAuth2Decorator(object): |
Instantiate and then use with oauth_required or oauth_aware |
as decorators on webapp.RequestHandler methods. |
- Example: |
+ :: |
decorator = OAuth2Decorator( |
client_id='837...ent.com', |
client_secret='Qh...wwI', |
scope='https://www.googleapis.com/auth/plus') |
- |
class MainHandler(webapp.RequestHandler): |
- |
@decorator.oauth_required |
def get(self): |
http = decorator.http() |
@@ -650,8 +666,9 @@ class OAuth2Decorator(object): |
provided to this constructor. A string indicating the name of the field |
on the _credentials_class where a Credentials object will be stored. |
Defaults to 'credentials'. |
- **kwargs: dict, Keyword arguments are be passed along as kwargs to the |
- OAuth2WebServerFlow constructor. |
+ **kwargs: dict, Keyword arguments are passed along as kwargs to |
+ the OAuth2WebServerFlow constructor. |
+ |
""" |
self._tls = threading.local() |
self.flow = None |
@@ -798,14 +815,18 @@ class OAuth2Decorator(object): |
url = self.flow.step1_get_authorize_url() |
return str(url) |
- def http(self): |
+ def http(self, *args, **kwargs): |
"""Returns an authorized http instance. |
Must only be called from within an @oauth_required decorated method, or |
from within an @oauth_aware decorated method where has_credentials() |
returns True. |
+ |
+ Args: |
+ *args: Positional arguments passed to httplib2.Http constructor. |
+ **kwargs: Positional arguments passed to httplib2.Http constructor. |
""" |
- return self.credentials.authorize(httplib2.Http()) |
+ return self.credentials.authorize(httplib2.Http(*args, **kwargs)) |
@property |
def callback_path(self): |
@@ -824,7 +845,8 @@ class OAuth2Decorator(object): |
def callback_handler(self): |
"""RequestHandler for the OAuth 2.0 redirect callback. |
- Usage: |
+ Usage:: |
+ |
app = webapp.WSGIApplication([ |
('/index', MyIndexHandler), |
..., |
@@ -858,7 +880,7 @@ class OAuth2Decorator(object): |
user) |
if decorator._token_response_param and credentials.token_response: |
- resp_json = simplejson.dumps(credentials.token_response) |
+ resp_json = json.dumps(credentials.token_response) |
redirect_uri = util._add_query_parameter( |
redirect_uri, decorator._token_response_param, resp_json) |
@@ -887,24 +909,23 @@ class OAuth2DecoratorFromClientSecrets(OAuth2Decorator): |
Uses a clientsecrets file as the source for all the information when |
constructing an OAuth2Decorator. |
- Example: |
+ :: |
decorator = OAuth2DecoratorFromClientSecrets( |
os.path.join(os.path.dirname(__file__), 'client_secrets.json') |
scope='https://www.googleapis.com/auth/plus') |
- |
class MainHandler(webapp.RequestHandler): |
- |
@decorator.oauth_required |
def get(self): |
http = decorator.http() |
# http is authorized with the user's Credentials and can be used |
# in API calls |
+ |
""" |
@util.positional(3) |
- def __init__(self, filename, scope, message=None, cache=None): |
+ def __init__(self, filename, scope, message=None, cache=None, **kwargs): |
"""Constructor |
Args: |
@@ -917,17 +938,20 @@ class OAuth2DecoratorFromClientSecrets(OAuth2Decorator): |
decorator. |
cache: An optional cache service client that implements get() and set() |
methods. See clientsecrets.loadfile() for details. |
+ **kwargs: dict, Keyword arguments are passed along as kwargs to |
+ the OAuth2WebServerFlow constructor. |
""" |
client_type, client_info = clientsecrets.loadfile(filename, cache=cache) |
if client_type not in [ |
clientsecrets.TYPE_WEB, clientsecrets.TYPE_INSTALLED]: |
raise InvalidClientSecretsError( |
- 'OAuth2Decorator doesn\'t support this OAuth 2.0 flow.') |
- constructor_kwargs = { |
- 'auth_uri': client_info['auth_uri'], |
- 'token_uri': client_info['token_uri'], |
- 'message': message, |
- } |
+ "OAuth2Decorator doesn't support this OAuth 2.0 flow.") |
+ constructor_kwargs = dict(kwargs) |
+ constructor_kwargs.update({ |
+ 'auth_uri': client_info['auth_uri'], |
+ 'token_uri': client_info['token_uri'], |
+ 'message': message, |
+ }) |
revoke_uri = client_info.get('revoke_uri') |
if revoke_uri is not None: |
constructor_kwargs['revoke_uri'] = revoke_uri |
@@ -960,4 +984,4 @@ def oauth2decorator_from_clientsecrets(filename, scope, |
""" |
return OAuth2DecoratorFromClientSecrets(filename, scope, |
- message=message, cache=cache) |
+ message=message, cache=cache) |