proxy token support - no tests

This commit is contained in:
Sandy Walsh 2011-09-09 06:33:38 -07:00
parent f7d38c2568
commit 2c3a865f6b
3 changed files with 70 additions and 20 deletions

@ -46,7 +46,8 @@ class HTTPClient(httplib2.Http):
self.region_name = region_name
self.management_url = None
self.auth_token = token
self.auth_token = None
self.proxy_token = token
# httplib2 overrides
self.force_exception_to_status_code = True
@ -76,7 +77,7 @@ class HTTPClient(httplib2.Http):
_logger.debug("RESP:%s %s\n", resp, body)
def request(self, *args, **kwargs):
kwargs.setdefault('headers', {})
kwargs.setdefault('headers', kwargs.get('headers', {}))
kwargs['headers']['User-Agent'] = self.USER_AGENT
if 'body' in kwargs:
kwargs['headers']['Content-Type'] = 'application/json'
@ -136,6 +137,48 @@ class HTTPClient(httplib2.Http):
def delete(self, url, **kwargs):
return self._cs_request(url, 'DELETE', **kwargs)
def _extract_service_catalog(self, url, resp, body):
"""See what the auth service told us and process the response.
We may get redirected to another site, fail or actually get
back a service catalog with a token and our endpoints."""
if resp.status == 200: # content must always present
try:
self.auth_url = url
self.service_catalog = \
service_catalog.ServiceCatalog(body)
self.auth_token = self.service_catalog.token.id
_logger.debug("***** REGION_NAME: %s" % self.region_name)
self.management_url = self.service_catalog.url_for(
'nova', 'public', attr='region',
filter_value=self.region_name)
_logger.debug("***** MANAGEMENT URL: %s" % self.management_url)
return None
except KeyError:
raise exceptions.AuthorizationFailure()
elif resp.status == 305:
return resp['location']
else:
raise exceptions.from_response(resp, body)
def _fetch_endpoints_from_auth(self, url):
"""We have a token, but don't know the final endpoint for
the region. We have to go back to the auth service and
ask again. This request requires an admin-level token
to work. The proxy token supplied could be from a low-level enduser.
This will overwrite our admin token with the user token.
"""
# GET /v2.0/tokens/#####/endpoints
token_url = urlparse.urljoin(url, "tokens", self.proxy_token,
"endpoints")
resp, body = self.request(token_url, "GET",
headers={'X-Auth_Token': self.auth_token},
body=body)
return self._extract_service_catalog(url, resp, body)
def authenticate(self):
scheme, netloc, path, query, frag = urlparse.urlsplit(
self.auth_url)
@ -149,6 +192,13 @@ class HTTPClient(httplib2.Http):
if self.version == "v2.0": # FIXME(chris): This should be better.
while auth_url:
auth_url = self._v2_auth(auth_url)
# Are we acting on behalf of another user via an
# existing token? If so, our actual endpoints may
# be different than that of the admin token.
if self.proxy_token:
return self._fetch_endpoints_from_auth()
else:
try:
while auth_url:
@ -162,6 +212,9 @@ class HTTPClient(httplib2.Http):
self._v2_auth(auth_url)
def _v1_auth(self, url):
if self.proxy_token:
raise NoTokenLookupException()
headers = {'X-Auth-User': self.user,
'X-Auth-Key': self.apikey}
if self.projectid:
@ -181,6 +234,7 @@ class HTTPClient(httplib2.Http):
raise exceptions.from_response(resp, body)
def _v2_auth(self, url):
"""Authenticate against a v2.0 auth service."""
body = {"passwordCredentials": {"username": self.user,
"password": self.apikey}}
@ -189,22 +243,7 @@ class HTTPClient(httplib2.Http):
token_url = urlparse.urljoin(url, "tokens")
resp, body = self.request(token_url, "POST", body=body)
if resp.status == 200: # content must always present
try:
self.auth_url = url
self.service_catalog = \
service_catalog.ServiceCatalog(body)
self.auth_token = self.service_catalog.token.id
self.management_url = self.service_catalog.url_for(
'nova', 'public', attr='region',
filter_value=self.region_name)
except KeyError:
raise exceptions.AuthorizationFailure()
elif resp.status == 305:
return resp['location']
else:
raise exceptions.from_response(resp, body)
return self._extract_service_catalog(url, resp, body)
def _munge_get_url(self, url):
"""

@ -12,6 +12,12 @@ class AuthorizationFailure(Exception):
pass
class NoTokenLookupException(Exception):
"""This form of authentication does not support looking up
endpoints from an existing token."""
pass
class ClientException(Exception):
"""
The base exception class for all exceptions this library raises.

@ -14,6 +14,11 @@ mock_request = mock.Mock(return_value=(fake_response, fake_body))
def get_client():
cl = client.HTTPClient("username", "apikey",
"project_id", "auth_test")
return cl
def get_authed_client():
cl = get_client()
cl.management_url = "http://example.com"
cl.auth_token = "token"
return cl
@ -22,7 +27,7 @@ def get_client():
class ClientTest(utils.TestCase):
def test_get(self):
cl = get_client()
cl = get_authed_client()
@mock.patch.object(httplib2.Http, "request", mock_request)
@mock.patch('time.time', mock.Mock(return_value=1234))
@ -40,7 +45,7 @@ class ClientTest(utils.TestCase):
test_get_call()
def test_post(self):
cl = get_client()
cl = get_authed_client()
@mock.patch.object(httplib2.Http, "request", mock_request)
def test_post_call():