Handle auth redirects

Our checking for keystone v2 and v3 was causing v2 tests to go down the
v1 code path. Fixing this surfaced a couple of long standing issues with
our v2/v3 handling of redirects and getting auth info.

This fixes our version identification, fixes extracting redirect
location for response headers, and returning the auth_url to calling
code.

Change-Id: I939ff027bf43e513e338bff1e99ca41fa52637b6
Closes-bug: #1825372
Signed-off-by: Sean McGinnis <sean.mcginnis@gmail.com>
This commit is contained in:
Sean McGinnis
2019-04-18 09:21:13 -05:00
parent 15295acb07
commit ffccfc0eca
2 changed files with 31 additions and 9 deletions

View File

@@ -286,7 +286,7 @@ class HTTPClient(object):
raise exceptions.EndpointNotFound() raise exceptions.EndpointNotFound()
self.auth_url = auth_url.rstrip('/') if auth_url else None self.auth_url = auth_url.rstrip('/') if auth_url else None
self.version = 'v1' self.ks_version = 'v1'
self.region_name = region_name self.region_name = region_name
self.endpoint_type = endpoint_type self.endpoint_type = endpoint_type
self.service_type = service_type self.service_type = service_type
@@ -486,6 +486,7 @@ class HTTPClient(object):
def _extract_service_catalog(self, url, resp, body, extract_token=True): def _extract_service_catalog(self, url, resp, body, extract_token=True):
"""See what the auth service told us and process the response. """See what the auth service told us and process the response.
We may get redirected to another site, fail or actually get We may get redirected to another site, fail or actually get
back a service catalog with a token and our endpoints. back a service catalog with a token and our endpoints.
""" """
@@ -520,7 +521,7 @@ class HTTPClient(object):
raise raise
elif resp.status_code == 305: elif resp.status_code == 305:
return resp['location'] return resp.headers['location']
else: else:
raise exceptions.from_response(resp, body) raise exceptions.from_response(resp, body)
@@ -557,7 +558,7 @@ class HTTPClient(object):
path_parts = path.split('/') path_parts = path.split('/')
for part in path_parts: for part in path_parts:
if len(part) > 0 and part[0] == 'v': if len(part) > 0 and part[0] == 'v':
self.version = part self.ks_version = part
break break
# TODO(sandy): Assume admin endpoint is 35357 for now. # TODO(sandy): Assume admin endpoint is 35357 for now.
@@ -567,7 +568,7 @@ class HTTPClient(object):
path, query, frag)) path, query, frag))
auth_url = self.auth_url auth_url = self.auth_url
if self.version == "v2.0" or self.version == "v3": if 'v2' in self.ks_version or 'v3' in self.ks_version:
while auth_url: while auth_url:
if not self.auth_system or self.auth_system == 'keystone': if not self.auth_system or self.auth_system == 'keystone':
auth_url = self._v2_or_v3_auth(auth_url) auth_url = self._v2_or_v3_auth(auth_url)
@@ -626,7 +627,7 @@ class HTTPClient(object):
def _v2_or_v3_auth(self, url): def _v2_or_v3_auth(self, url):
"""Authenticate against a v2.0 auth service.""" """Authenticate against a v2.0 auth service."""
if self.version == "v3": if self.ks_version == "v3":
body = { body = {
"auth": { "auth": {
"identity": { "identity": {
@@ -653,11 +654,11 @@ class HTTPClient(object):
body['auth']['tenantName'] = self.projectid body['auth']['tenantName'] = self.projectid
elif self.tenant_id: elif self.tenant_id:
body['auth']['tenantId'] = self.tenant_id body['auth']['tenantId'] = self.tenant_id
self._authenticate(url, body) return self._authenticate(url, body)
def _authenticate(self, url, body): def _authenticate(self, url, body):
"""Authenticate and extract the service catalog.""" """Authenticate and extract the service catalog."""
if self.version == 'v3': if self.ks_version == 'v3':
token_url = url + "/auth/tokens" token_url = url + "/auth/tokens"
else: else:
token_url = url + "/tokens" token_url = url + "/tokens"

View File

@@ -21,6 +21,28 @@ from cinderclient import exceptions
from cinderclient.tests.unit import utils from cinderclient.tests.unit import utils
fake_auth_response = {
"access": {
"token": {
"expires": "2014-11-01T03:32:15-05:00",
"id": "FAKE_ID",
},
"serviceCatalog": [
{
"type": "volumev2",
"endpoints": [
{
"adminURL": "http://localhost:8776/v2",
"region": "RegionOne",
"internalURL": "http://localhost:8776/v2",
"publicURL": "http://localhost:8776/v2",
},
],
},
],
},
}
fake_response = utils.TestResponse({ fake_response = utils.TestResponse({
"status_code": 200, "status_code": 200,
"text": '{"hi": "there"}', "text": '{"hi": "there"}',
@@ -29,7 +51,7 @@ mock_request = mock.Mock(return_value=(fake_response))
fake_201_response = utils.TestResponse({ fake_201_response = utils.TestResponse({
"status_code": 201, "status_code": 201,
"text": '{"hi": "there"}', "text": json.dumps(fake_auth_response),
}) })
mock_201_request = mock.Mock(return_value=(fake_201_response)) mock_201_request = mock.Mock(return_value=(fake_201_response))
@@ -329,7 +351,6 @@ class ClientTest(utils.TestCase):
cl = get_authed_client() cl = get_authed_client()
cl.auth_url = 'http://example.com:5000/v3' cl.auth_url = 'http://example.com:5000/v3'
@mock.patch.object(cl, "_extract_service_catalog", mock.Mock())
@mock.patch.object(requests, "request", mock_201_request) @mock.patch.object(requests, "request", mock_201_request)
def test_auth_call(): def test_auth_call():
cl.authenticate() cl.authenticate()