From b124d19ab4ca43923e56e87a02da9adde1ac033d Mon Sep 17 00:00:00 2001 From: Ben Demaree Date: Thu, 24 Mar 2016 13:48:27 -0500 Subject: [PATCH] Populate token expiry for GCE credentials Populates the token_expiry property for GCE App Assertion credentials (thus enabling access_token_expired). This corrects assumptions like the one in the access_token_expired property on GCE specifically: it's stated there "If the token_expiry isn't set, we assume the token doesn't expire" which seems to be incorrect for tokens retrieved from the GCE Metadata service. Remove usage of _UTCNOW --- oauth2client/contrib/gce.py | 3 +++ tests/contrib/test_gce.py | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/oauth2client/contrib/gce.py b/oauth2client/contrib/gce.py index 6542008e0..e12ec0526 100644 --- a/oauth2client/contrib/gce.py +++ b/oauth2client/contrib/gce.py @@ -17,6 +17,7 @@ Utilities for making it easier to use OAuth 2.0 on Google Compute Engine. """ +import datetime import json import logging import warnings @@ -135,6 +136,8 @@ def _refresh(self, http_request): raise HttpAccessTokenRefreshError(str(e), status=response.status) self.access_token = token_content['access_token'] + delta = datetime.timedelta(seconds=int(token_content['expires_in'])) + self.token_expiry = delta + datetime.datetime.utcnow() else: if response.status == http_client.NOT_FOUND: content += (' This can occur if a VM was created' diff --git a/tests/contrib/test_gce.py b/tests/contrib/test_gce.py index 48da97632..006e0b6e0 100644 --- a/tests/contrib/test_gce.py +++ b/tests/contrib/test_gce.py @@ -15,6 +15,7 @@ """Unit tests for oauth2client.contrib.gce.""" import json +from datetime import datetime from six.moves import http_client from six.moves import urllib import unittest2 @@ -62,7 +63,11 @@ def test_to_json_and_from_json(self): def _refresh_success_helper(self, bytes_response=False): access_token = u'this-is-a-token' - return_val = json.dumps({u'access_token': access_token}) + expires_in = 600 + return_val = json.dumps({ + u'access_token': access_token, + u'expires_in': expires_in + }) if bytes_response: return_val = _to_bytes(return_val) http = mock.MagicMock() @@ -73,6 +78,8 @@ def _refresh_success_helper(self, bytes_response=False): self.assertEquals(None, credentials.access_token) credentials.refresh(http) self.assertEquals(access_token, credentials.access_token) + self.assertFalse(credentials.access_token_expired) + self.assertTrue(credentials.token_expiry > datetime.utcnow()) base_metadata_uri = ( 'http://metadata.google.internal/computeMetadata/v1/instance/' @@ -200,12 +207,13 @@ def test_get_access_token(self): http = mock.MagicMock() http.request = mock.MagicMock( return_value=(mock.Mock(status=http_client.OK), - '{"access_token": "this-is-a-token"}')) + '{"access_token": "this-is-a-token", ' + '"expires_in": 600}')) credentials = AppAssertionCredentials() token = credentials.get_access_token(http=http) self.assertEqual('this-is-a-token', token.access_token) - self.assertEqual(None, token.expires_in) + self.assertGreaterEqual(600, token.expires_in) http.request.assert_called_once_with( 'http://metadata.google.internal/computeMetadata/v1/instance/'