aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiran Nuna <liranuna@gmail.com>2016-10-06 12:53:16 -0700
committerJon Wayne Parrott <jonwayne@google.com>2016-10-06 12:53:16 -0700
commit999de3ac8bf377b511824f1ec88c651dde5a1d4f (patch)
treeb3e235240361323a4ac05074c921d6b7388f308d
parent3f9fdbd5a3e590e6e53e42a59ca96d1010c0cec7 (diff)
downloadoauth2client-999de3ac8bf377b511824f1ec88c651dde5a1d4f.tar.gz
Try to revoke token with POST when getting a 405 (#662)
The OAuth spec does not specify the HTTP verb explicitly but it does hint that POST is the correct verb. When using the client library with other OAuth services that implement revocation token via a POST, revoking the token will fail. This commit adds the ability to re-try the revocation process if we get a 405 with the POST verb.
-rw-r--r--oauth2client/client.py4
-rw-r--r--tests/test_client.py58
2 files changed, 43 insertions, 19 deletions
diff --git a/oauth2client/client.py b/oauth2client/client.py
index 704c610..0a1aff9 100644
--- a/oauth2client/client.py
+++ b/oauth2client/client.py
@@ -836,6 +836,10 @@ class OAuth2Credentials(Credentials):
token_revoke_uri = _helpers.update_query_params(
self.revoke_uri, query_params)
resp, content = transport.request(http, token_revoke_uri)
+ if resp.status == http_client.METHOD_NOT_ALLOWED:
+ body = urllib.parse.urlencode(query_params)
+ resp, content = transport.request(http, token_revoke_uri,
+ method='POST', body=body)
if resp.status == http_client.OK:
self.invalid = True
else:
diff --git a/tests/test_client.py b/tests/test_client.py
index a3268ba..786b818 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -819,8 +819,8 @@ class DummyDeleteStorage(client.Storage):
self.delete_called = True
-def _token_revoke_test_helper(testcase, status, revoke_raise,
- valid_bool_value, token_attr):
+def _token_revoke_test_helper(testcase, revoke_raise, valid_bool_value,
+ token_attr, http_mock):
current_store = getattr(testcase.credentials, 'store', None)
dummy_store = DummyDeleteStorage()
@@ -834,12 +834,11 @@ def _token_revoke_test_helper(testcase, status, revoke_raise,
return actual_do_revoke(http, token)
testcase.credentials._do_revoke = do_revoke_stub
- http = http_mock.HttpMock(headers={'status': status})
if revoke_raise:
testcase.assertRaises(client.TokenRevokeError,
- testcase.credentials.revoke, http)
+ testcase.credentials.revoke, http_mock)
else:
- testcase.credentials.revoke(http)
+ testcase.credentials.revoke(http_mock)
testcase.assertEqual(getattr(testcase.credentials, token_attr),
testcase.token_from_revoke)
@@ -922,21 +921,38 @@ class BasicCredentialsTests(unittest.TestCase):
self.assertEqual(None, self.credentials.token_response)
def test_token_revoke_success(self):
+ http = http_mock.HttpMock(headers={'status': http_client.OK})
_token_revoke_test_helper(
- self, '200', revoke_raise=False,
- valid_bool_value=True, token_attr='refresh_token')
+ self, revoke_raise=False, valid_bool_value=True,
+ token_attr='refresh_token', http_mock=http)
def test_token_revoke_failure(self):
+ http = http_mock.HttpMock(headers={'status': http_client.BAD_REQUEST})
_token_revoke_test_helper(
- self, '400', revoke_raise=True,
- valid_bool_value=False, token_attr='refresh_token')
+ self, revoke_raise=True, valid_bool_value=False,
+ token_attr='refresh_token', http_mock=http)
def test_token_revoke_fallback(self):
original_credentials = self.credentials.to_json()
self.credentials.refresh_token = None
+
+ http = http_mock.HttpMock(headers={'status': http_client.OK})
+ _token_revoke_test_helper(
+ self, revoke_raise=False, valid_bool_value=True,
+ token_attr='access_token', http_mock=http)
+ self.credentials = self.credentials.from_json(original_credentials)
+
+ def test_token_revoke_405(self):
+ original_credentials = self.credentials.to_json()
+ self.credentials.refresh_token = None
+
+ http = http_mock.HttpMockSequence([
+ ({'status': http_client.METHOD_NOT_ALLOWED}, b''),
+ ({'status': http_client.OK}, b''),
+ ])
_token_revoke_test_helper(
- self, '200', revoke_raise=False,
- valid_bool_value=True, token_attr='access_token')
+ self, revoke_raise=False, valid_bool_value=True,
+ token_attr='access_token', http_mock=http)
self.credentials = self.credentials.from_json(original_credentials)
def test_non_401_error_response(self):
@@ -1483,14 +1499,16 @@ class AccessTokenCredentialsTests(unittest.TestCase):
resp, content = transport.request(http, 'http://example.com')
def test_token_revoke_success(self):
+ http = http_mock.HttpMock(headers={'status': http_client.OK})
_token_revoke_test_helper(
- self, '200', revoke_raise=False,
- valid_bool_value=True, token_attr='access_token')
+ self, revoke_raise=False, valid_bool_value=True,
+ token_attr='access_token', http_mock=http)
def test_token_revoke_failure(self):
+ http = http_mock.HttpMock(headers={'status': http_client.BAD_REQUEST})
_token_revoke_test_helper(
- self, '400', revoke_raise=True,
- valid_bool_value=False, token_attr='access_token')
+ self, revoke_raise=True, valid_bool_value=False,
+ token_attr='access_token', http_mock=http)
def test_non_401_error_response(self):
http = http_mock.HttpMock(headers={'status': http_client.BAD_REQUEST})
@@ -1543,14 +1561,16 @@ class TestAssertionCredentials(unittest.TestCase):
self.assertEqual(b'Bearer 1/3w', content[b'Authorization'])
def test_token_revoke_success(self):
+ http = http_mock.HttpMock(headers={'status': http_client.OK})
_token_revoke_test_helper(
- self, '200', revoke_raise=False,
- valid_bool_value=True, token_attr='access_token')
+ self, revoke_raise=False, valid_bool_value=True,
+ token_attr='access_token', http_mock=http)
def test_token_revoke_failure(self):
+ http = http_mock.HttpMock(headers={'status': http_client.BAD_REQUEST})
_token_revoke_test_helper(
- self, '400', revoke_raise=True,
- valid_bool_value=False, token_attr='access_token')
+ self, revoke_raise=True, valid_bool_value=False,
+ token_attr='access_token', http_mock=http)
def test_sign_blob_abstract(self):
credentials = client.AssertionCredentials(None)