Steps to reproduce:
1. Create SignedJwtAssertionCredentials(), use them to make an API call and put
them in storage
2. Retrieve the credentials from storage after 5 minutes
3. Examine the credentials.token_expiry field
You would expect to see the expiration of the token (an hour for service
accounts). Instead the value is null.
Example code to reproduce:
===========================
storage = StorageByKeyName(CredentialsModel, credKey, 'credentials',
cache=memcache)
credentials = SignedJwtAssertionCredentials( config.SERVICE_EMAIL,
config.SERVICE_KEY,
scope='https://www.googleapis.com/auth/calendar',
sub=accountObj.email )
storage.put(credentials)
credentials.set_store(storage)
http = httplib2.Http(cache=memcache, timeout=60)
http = credentials.authorize(http)
service = build('calendar', 'v3', http=http)
....
do something with calendar service
5 minutes later get the credentials out of storage
.....
credentials = storage.get()
print credentials.token_expiry
============================
The missing token_expiry is significant because this value is used by
access_token_expired(). If token_expiry is None then access_token_expired()
returns False, even though in reality the token may in fact be expired. This in
turn leads to needless extra API calls, because when a request is made with an
expired token a 401 result is returned and then the token must be refreshed.
If token_expiry was maintained correctly and access_token_expired() returned an
accurate result then a developer could know in advance to refresh the token and
make only 1 API call instead of having to make a call and then get a 401 and
then refresh and then make the call again.
The problem is in the from_json() method of SignedJwtAssertionCredentials.
The following code fixes the issue:
class SignedJwtAssertionCredentials(AssertionCredentials):
....
@classmethod
def from_json(cls, s):
data = simplejson.loads(s)
retval = SignedJwtAssertionCredentials(
data['service_account_name'],
base64.b64decode(data['private_key']),
data['scope'],
private_key_password=data['private_key_password'],
user_agent=data['user_agent'],
token_uri=data['token_uri'],
**data['kwargs']
)
retval.invalid = data['invalid']
retval.access_token = data['access_token']
# ========= ADD THESE LINESE TO CORRECTLY RESTORE THE TOKEN_EXPIRY ===========
if 'token_expiry' in data and not isinstance(data['token_expiry'], datetime.datetime):
try:
retval.token_expiry = datetime.datetime.strptime(data['token_expiry'], EXPIRY_FORMAT)
except:
retval.token_expiry = None
#==============================
return retval
Original issue reported on code.google.com by henne...@gmail.com on 11 Mar 2014 at 1:45
Original issue reported on code.google.com by
henne...@gmail.com
on 11 Mar 2014 at 1:45