From 4a81a146859cf783c876dc0e8d580333c246596c Mon Sep 17 00:00:00 2001 From: Jamie Lennox Date: Fri, 4 Apr 2014 11:17:24 +1000 Subject: [PATCH] Add new error for invalid response There are a number of places where we expect a certain format of response. If it's not found we often end up raising a KeyError when accessing data. Create a new Exception type that is raised when a HTTP response is not appropriate for parsing and use it within authentication calls. Closes-Bug: #1307306 Change-Id: I3cf2db07a8e76ee17702130e9efb0edf640d293a --- keystoneclient/auth/identity/base.py | 1 + keystoneclient/auth/identity/v2.py | 8 ++++++- keystoneclient/auth/identity/v3.py | 8 ++++++- keystoneclient/exceptions.py | 8 +++++++ keystoneclient/tests/auth/test_identity_v2.py | 22 +++++++++++++++++++ keystoneclient/tests/auth/test_identity_v3.py | 22 +++++++++++++++++++ 6 files changed, 67 insertions(+), 2 deletions(-) diff --git a/keystoneclient/auth/identity/base.py b/keystoneclient/auth/identity/base.py index d0b155eb..9554c534 100644 --- a/keystoneclient/auth/identity/base.py +++ b/keystoneclient/auth/identity/base.py @@ -58,6 +58,7 @@ class BaseIdentityPlugin(base.BaseAuthPlugin): when invoked. If you are looking to just retrieve the current auth data then you should use get_access. + :raises InvalidResponse: The response returned wasn't appropriate. :raises HttpError: An error from an invalid HTTP response. :returns AccessInfo: Token access information. diff --git a/keystoneclient/auth/identity/v2.py b/keystoneclient/auth/identity/v2.py index 1a6564f1..bd3bade5 100644 --- a/keystoneclient/auth/identity/v2.py +++ b/keystoneclient/auth/identity/v2.py @@ -84,7 +84,13 @@ class Auth(base.BaseIdentityPlugin): resp = session.post(url, json=params, headers=headers, authenticated=False) - return access.AccessInfoV2(**resp.json()['access']) + + try: + resp_data = resp.json()['access'] + except (KeyError, ValueError): + raise exceptions.InvalidResponse(response=resp) + + return access.AccessInfoV2(**resp_data) @abc.abstractmethod def get_auth_data(self, headers=None): diff --git a/keystoneclient/auth/identity/v3.py b/keystoneclient/auth/identity/v3.py index 93299251..747bbda6 100644 --- a/keystoneclient/auth/identity/v3.py +++ b/keystoneclient/auth/identity/v3.py @@ -108,8 +108,14 @@ class Auth(base.BaseIdentityPlugin): resp = session.post(self.token_url, json=body, headers=headers, authenticated=False) + + try: + resp_data = resp.json()['token'] + except (KeyError, ValueError): + raise exceptions.InvalidResponse(response=resp) + return access.AccessInfoV3(resp.headers['X-Subject-Token'], - **resp.json()['token']) + **resp_data) @staticmethod def _factory(auth_url, **kwargs): diff --git a/keystoneclient/exceptions.py b/keystoneclient/exceptions.py index d9d3f382..4572af92 100644 --- a/keystoneclient/exceptions.py +++ b/keystoneclient/exceptions.py @@ -61,3 +61,11 @@ class MissingAuthPlugin(ClientException): class NoMatchingPlugin(ClientException): """There were no auth plugins that could be created from the parameters provided.""" + + +class InvalidResponse(ClientException): + """The response from the server is not valid for this request.""" + + def __init__(self, response): + super(InvalidResponse, self).__init__() + self.response = response diff --git a/keystoneclient/tests/auth/test_identity_v2.py b/keystoneclient/tests/auth/test_identity_v2.py index 23729119..3f1c45e2 100644 --- a/keystoneclient/tests/auth/test_identity_v2.py +++ b/keystoneclient/tests/auth/test_identity_v2.py @@ -211,3 +211,25 @@ class V2IdentityPlugin(utils.TestCase): endpoint_filter={'service_type': 'compute'}) self.assertEqual(resp.status_code, 200) self.assertEqual(resp.text, 'SUCCESS') + + @httpretty.activate + def test_invalid_auth_response_dict(self): + self.stub_auth(json={'hello': 'world'}) + + a = v2.Password(self.TEST_URL, username=self.TEST_USER, + password=self.TEST_PASS) + s = session.Session(auth=a) + + self.assertRaises(exceptions.InvalidResponse, s.get, 'http://any', + authenticated=True) + + @httpretty.activate + def test_invalid_auth_response_type(self): + self.stub_url(httpretty.POST, ['tokens'], body='testdata') + + a = v2.Password(self.TEST_URL, username=self.TEST_USER, + password=self.TEST_PASS) + s = session.Session(auth=a) + + self.assertRaises(exceptions.InvalidResponse, s.get, 'http://any', + authenticated=True) diff --git a/keystoneclient/tests/auth/test_identity_v3.py b/keystoneclient/tests/auth/test_identity_v3.py index ca51ef7c..e29c353b 100644 --- a/keystoneclient/tests/auth/test_identity_v3.py +++ b/keystoneclient/tests/auth/test_identity_v3.py @@ -366,3 +366,25 @@ class V3IdentityPlugin(utils.TestCase): endpoint_filter={'service_type': 'compute'}) self.assertEqual(resp.status_code, 200) self.assertEqual(resp.text, 'SUCCESS') + + @httpretty.activate + def test_invalid_auth_response_dict(self): + self.stub_auth(json={'hello': 'world'}) + + a = v3.Password(self.TEST_URL, username=self.TEST_USER, + password=self.TEST_PASS) + s = session.Session(auth=a) + + self.assertRaises(exceptions.InvalidResponse, s.get, 'http://any', + authenticated=True) + + @httpretty.activate + def test_invalid_auth_response_type(self): + self.stub_url(httpretty.POST, ['auth', 'tokens'], body='testdata') + + a = v3.Password(self.TEST_URL, username=self.TEST_USER, + password=self.TEST_PASS) + s = session.Session(auth=a) + + self.assertRaises(exceptions.InvalidResponse, s.get, 'http://any', + authenticated=True)