Handle URLs via the session and auth_plugins
In the future clients will simply pass the service they expect to talk to and the path. This will prevent every service trying to get their own base urls from the service catalog individually. This can later be extended to have the auth plugin actually contact the URL from the service catalog which will let us have unversioned endpoints in the catalog handled from a single location. Change-Id: I80f0b5b1dbb45565fec09d1cb2c0552cfb9a72f5 blueprint: auth-plugin-endpoints
This commit is contained in:

committed by
Dolph Mathews

parent
c1ddc5e199
commit
b07fbb91c6
@@ -34,3 +34,22 @@ class BaseAuthPlugin(object):
|
||||
:param session: A session object so the plugin can make HTTP calls.
|
||||
:return string: A token to use.
|
||||
"""
|
||||
|
||||
def get_endpoint(self, session, **kwargs):
|
||||
"""Return an endpoint for the client.
|
||||
|
||||
There are no required keyword arguments to ``get_endpoint`` as a plugin
|
||||
implementation should use best effort with the information available to
|
||||
determine the endpoint. However there are certain standard options that
|
||||
will be generated by the clients and should be used by plugins:
|
||||
|
||||
- ``service_type``: what sort of service is required.
|
||||
- ``interface``: what visibility the endpoint should have.
|
||||
- ``region_name``: the region the endpoint exists in.
|
||||
|
||||
:param Session session: The session object that the auth_plugin
|
||||
belongs to.
|
||||
|
||||
:returns string: The base URL that will be used to talk to the
|
||||
required service or None if not available.
|
||||
"""
|
||||
|
@@ -90,3 +90,37 @@ class BaseIdentityPlugin(base.BaseAuthPlugin):
|
||||
self.auth_ref = self.get_auth_ref(session, **kwargs)
|
||||
|
||||
return self.auth_ref
|
||||
|
||||
def get_endpoint(self, session, service_type=None, interface=None,
|
||||
region_name=None, **kwargs):
|
||||
"""Return a valid endpoint for a service.
|
||||
|
||||
If a valid token is not present then a new one will be fetched using
|
||||
the session and kwargs.
|
||||
|
||||
:param string service_type: The type of service to lookup the endpoint
|
||||
for. This plugin will return None (failure)
|
||||
if service_type is not provided.
|
||||
:param string interface: The exposure of the endpoint. Should be
|
||||
`public`, `internal` or `admin`.
|
||||
Defaults to `public`.
|
||||
:param string region_name: The region the endpoint should exist in.
|
||||
(optional)
|
||||
|
||||
:raises HTTPError: An error from an invalid HTTP response.
|
||||
|
||||
:return string or None: A valid endpoint URL or None if not available.
|
||||
"""
|
||||
if not service_type:
|
||||
LOG.warn('Plugin cannot return an endpoint without knowing the '
|
||||
'service type that is required. Add service_type to '
|
||||
'endpoint filtering data.')
|
||||
return None
|
||||
|
||||
if not interface:
|
||||
interface = 'public'
|
||||
|
||||
service_catalog = self.get_access(session).service_catalog
|
||||
return service_catalog.url_for(service_type=service_type,
|
||||
endpoint_type=interface,
|
||||
region_name=region_name)
|
||||
|
@@ -250,6 +250,12 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
||||
if self.auth_token_from_user:
|
||||
return self.auth_token_from_user
|
||||
|
||||
def get_endpoint(self, session, interface=None, **kwargs):
|
||||
if interface == 'public':
|
||||
return self.auth_url
|
||||
else:
|
||||
return self.management_url
|
||||
|
||||
@auth_token.setter
|
||||
def auth_token(self, value):
|
||||
"""Override the auth_token.
|
||||
@@ -554,25 +560,27 @@ class HTTPClient(baseclient.Client, base.BaseAuthPlugin):
|
||||
resp = super(HTTPClient, self).request(url, method, **kwargs)
|
||||
return resp, self._decode_body(resp)
|
||||
|
||||
def _cs_request(self, url, method, **kwargs):
|
||||
def _cs_request(self, url, method, management=True, **kwargs):
|
||||
"""Makes an authenticated request to keystone endpoint by
|
||||
concatenating self.management_url and url and passing in method and
|
||||
any associated kwargs.
|
||||
"""
|
||||
interface = 'admin' if management else 'public'
|
||||
endpoint_filter = kwargs.setdefault('endpoint_filter', {})
|
||||
endpoint_filter.setdefault('service_type', 'identity')
|
||||
endpoint_filter.setdefault('interface', interface)
|
||||
|
||||
is_management = kwargs.pop('management', True)
|
||||
|
||||
if is_management and self.management_url is None:
|
||||
raise exceptions.AuthorizationFailure(
|
||||
'Current authorization does not have a known management url')
|
||||
|
||||
url_to_use = self.auth_url
|
||||
if is_management:
|
||||
url_to_use = self.management_url
|
||||
if self.region_name:
|
||||
endpoint_filter.setdefault('region_name', self.region_name)
|
||||
|
||||
kwargs.setdefault('authenticated', None)
|
||||
return self.request(url_to_use + url, method,
|
||||
**kwargs)
|
||||
try:
|
||||
return self.request(url, method, **kwargs)
|
||||
except exceptions.MissingAuthPlugin:
|
||||
_logger.info('Cannot get authenticated endpoint without an '
|
||||
'auth plugin')
|
||||
raise exceptions.AuthorizationFailure(
|
||||
'Current authorization does not have a known management url')
|
||||
|
||||
def get(self, url, **kwargs):
|
||||
return self._cs_request(url, 'GET', **kwargs)
|
||||
|
@@ -14,6 +14,7 @@ import logging
|
||||
|
||||
import requests
|
||||
import six
|
||||
from six.moves import urllib
|
||||
|
||||
from keystoneclient import exceptions
|
||||
from keystoneclient.openstack.common import jsonutils
|
||||
@@ -110,7 +111,7 @@ class Session(object):
|
||||
|
||||
def request(self, url, method, json=None, original_ip=None,
|
||||
user_agent=None, redirect=None, authenticated=None,
|
||||
**kwargs):
|
||||
endpoint_filter=None, **kwargs):
|
||||
"""Send an HTTP request with the specified characteristics.
|
||||
|
||||
Wrapper around `requests.Session.request` to handle tasks such as
|
||||
@@ -119,7 +120,11 @@ class Session(object):
|
||||
Arguments that are not handled are passed through to the requests
|
||||
library.
|
||||
|
||||
:param string url: Fully qualified URL of HTTP request
|
||||
:param string url: Path or fully qualified URL of HTTP request. If only
|
||||
a path is provided then endpoint_filter must also be
|
||||
provided such that the base URL can be determined.
|
||||
If a fully qualified URL is provided then
|
||||
endpoint_filter will be ignored.
|
||||
:param string method: The http method to use. (eg. 'GET', 'POST')
|
||||
:param string original_ip: Mark this request as forwarded for this ip.
|
||||
(optional)
|
||||
@@ -136,6 +141,11 @@ class Session(object):
|
||||
request, False if not or None for attach if
|
||||
an auth_plugin is available.
|
||||
(optional, defaults to None)
|
||||
:param dict endpoint_filter: Data to be provided to an auth plugin with
|
||||
which it should be able to determine an
|
||||
endpoint to use for this request. If not
|
||||
provided then URL is expected to be a
|
||||
fully qualified URL. (optional)
|
||||
:param kwargs: any other parameter that can be passed to
|
||||
requests.Session.request (such as `headers`). Except:
|
||||
'data' will be overwritten by the data in 'json' param.
|
||||
@@ -161,6 +171,19 @@ class Session(object):
|
||||
|
||||
headers['X-Auth-Token'] = token
|
||||
|
||||
# if we are passed a fully qualified URL and a endpoint_filter we
|
||||
# should ignore the filter. This will make it easier for clients who
|
||||
# want to overrule the default endpoint_filter data added to all client
|
||||
# requests. We check fully qualified here by the presence of a host.
|
||||
url_data = urllib.parse.urlparse(url)
|
||||
if endpoint_filter and not url_data.netloc:
|
||||
base_url = self.get_endpoint(**endpoint_filter)
|
||||
|
||||
if not base_url:
|
||||
raise exceptions.EndpointNotFound()
|
||||
|
||||
url = '%s/%s' % (base_url.rstrip('/'), url.lstrip('/'))
|
||||
|
||||
if self.cert:
|
||||
kwargs.setdefault('cert', self.cert)
|
||||
|
||||
@@ -344,3 +367,11 @@ class Session(object):
|
||||
except exceptions.HTTPError as exc:
|
||||
raise exceptions.AuthorizationFailure("Authentication failure: "
|
||||
"%s" % exc)
|
||||
|
||||
def get_endpoint(self, **kwargs):
|
||||
"""Get an endpoint as provided by the auth plugin."""
|
||||
if not self.auth:
|
||||
raise exceptions.MissingAuthPlugin('An auth plugin is required to '
|
||||
'determine the endpoint URL.')
|
||||
|
||||
return self.auth.get_endpoint(self, **kwargs)
|
||||
|
0
keystoneclient/tests/auth/__init__.py
Normal file
0
keystoneclient/tests/auth/__init__.py
Normal file
@@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
|
||||
import httpretty
|
||||
from six.moves import urllib
|
||||
|
||||
from keystoneclient.auth.identity import v2
|
||||
from keystoneclient import exceptions
|
||||
@@ -29,7 +30,52 @@ class V2IdentityPlugin(utils.TestCase):
|
||||
|
||||
TEST_PASS = 'password'
|
||||
|
||||
TEST_SERVICE_CATALOG = []
|
||||
TEST_SERVICE_CATALOG = [{
|
||||
"endpoints": [{
|
||||
"adminURL": "http://cdn.admin-nets.local:8774/v1.0",
|
||||
"region": "RegionOne",
|
||||
"internalURL": "http://127.0.0.1:8774/v1.0",
|
||||
"publicURL": "http://cdn.admin-nets.local:8774/v1.0/"
|
||||
}],
|
||||
"type": "nova_compat",
|
||||
"name": "nova_compat"
|
||||
}, {
|
||||
"endpoints": [{
|
||||
"adminURL": "http://nova/novapi/admin",
|
||||
"region": "RegionOne",
|
||||
"internalURL": "http://nova/novapi/internal",
|
||||
"publicURL": "http://nova/novapi/public"
|
||||
}],
|
||||
"type": "compute",
|
||||
"name": "nova"
|
||||
}, {
|
||||
"endpoints": [{
|
||||
"adminURL": "http://glance/glanceapi/admin",
|
||||
"region": "RegionOne",
|
||||
"internalURL": "http://glance/glanceapi/internal",
|
||||
"publicURL": "http://glance/glanceapi/public"
|
||||
}],
|
||||
"type": "image",
|
||||
"name": "glance"
|
||||
}, {
|
||||
"endpoints": [{
|
||||
"adminURL": TEST_ADMIN_URL,
|
||||
"region": "RegionOne",
|
||||
"internalURL": "http://127.0.0.1:5000/v2.0",
|
||||
"publicURL": "http://127.0.0.1:5000/v2.0"
|
||||
}],
|
||||
"type": "identity",
|
||||
"name": "keystone"
|
||||
}, {
|
||||
"endpoints": [{
|
||||
"adminURL": "http://swift/swiftapi/admin",
|
||||
"region": "RegionOne",
|
||||
"internalURL": "http://swift/swiftapi/internal",
|
||||
"publicURL": "http://swift/swiftapi/public"
|
||||
}],
|
||||
"type": "object-store",
|
||||
"name": "swift"
|
||||
}]
|
||||
|
||||
def setUp(self):
|
||||
super(V2IdentityPlugin, self).setUp()
|
||||
@@ -109,3 +155,55 @@ class V2IdentityPlugin(utils.TestCase):
|
||||
|
||||
self.assertRequestBodyIs(json=req)
|
||||
self.assertEqual(s.auth.auth_ref.auth_token, self.TEST_TOKEN)
|
||||
|
||||
@httpretty.activate
|
||||
def _do_service_url_test(self, base_url, endpoint_filter):
|
||||
self.stub_auth(json=self.TEST_RESPONSE_DICT)
|
||||
self.stub_url(httpretty.GET, ['path'],
|
||||
base_url=base_url,
|
||||
body='SUCCESS', status=200)
|
||||
|
||||
a = v2.Password(self.TEST_URL, username=self.TEST_USER,
|
||||
password=self.TEST_PASS)
|
||||
s = session.Session(auth=a)
|
||||
|
||||
resp = s.get('/path', endpoint_filter=endpoint_filter)
|
||||
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
path = "%s/%s" % (urllib.parse.urlparse(base_url).path, 'path')
|
||||
self.assertEqual(httpretty.last_request().path, path)
|
||||
|
||||
def test_service_url(self):
|
||||
endpoint_filter = {'service_type': 'compute', 'interface': 'admin'}
|
||||
self._do_service_url_test('http://nova/novapi/admin', endpoint_filter)
|
||||
|
||||
def test_service_url_defaults_to_public(self):
|
||||
endpoint_filter = {'service_type': 'compute'}
|
||||
self._do_service_url_test('http://nova/novapi/public', endpoint_filter)
|
||||
|
||||
@httpretty.activate
|
||||
def test_endpoint_filter_without_service_type_fails(self):
|
||||
self.stub_auth(json=self.TEST_RESPONSE_DICT)
|
||||
|
||||
a = v2.Password(self.TEST_URL, username=self.TEST_USER,
|
||||
password=self.TEST_PASS)
|
||||
s = session.Session(auth=a)
|
||||
|
||||
self.assertRaises(exceptions.EndpointNotFound, s.get, '/path',
|
||||
endpoint_filter={'interface': 'admin'})
|
||||
|
||||
@httpretty.activate
|
||||
def test_full_url_overrides_endpoint_filter(self):
|
||||
self.stub_auth(json=self.TEST_RESPONSE_DICT)
|
||||
self.stub_url(httpretty.GET, [],
|
||||
base_url='http://testurl/',
|
||||
body='SUCCESS', status=200)
|
||||
|
||||
a = v2.Password(self.TEST_URL, username=self.TEST_USER,
|
||||
password=self.TEST_PASS)
|
||||
s = session.Session(auth=a)
|
||||
|
||||
resp = s.get('http://testurl/',
|
||||
endpoint_filter={'service_type': 'compute'})
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertEqual(resp.text, 'SUCCESS')
|
||||
|
@@ -15,6 +15,7 @@
|
||||
import copy
|
||||
|
||||
import httpretty
|
||||
from six.moves import urllib
|
||||
|
||||
from keystoneclient import access
|
||||
from keystoneclient.auth.identity import v3
|
||||
@@ -32,7 +33,83 @@ class V3IdentityPlugin(utils.TestCase):
|
||||
|
||||
TEST_PASS = 'password'
|
||||
|
||||
TEST_SERVICE_CATALOG = []
|
||||
TEST_SERVICE_CATALOG = [{
|
||||
"endpoints": [{
|
||||
"url": "http://cdn.admin-nets.local:8774/v1.0/",
|
||||
"region": "RegionOne",
|
||||
"interface": "public"
|
||||
}, {
|
||||
"url": "http://127.0.0.1:8774/v1.0",
|
||||
"region": "RegionOne",
|
||||
"interface": "internal"
|
||||
}, {
|
||||
"url": "http://cdn.admin-nets.local:8774/v1.0",
|
||||
"region": "RegionOne",
|
||||
"interface": "admin"
|
||||
}],
|
||||
"type": "nova_compat"
|
||||
}, {
|
||||
"endpoints": [{
|
||||
"url": "http://nova/novapi/public",
|
||||
"region": "RegionOne",
|
||||
"interface": "public"
|
||||
}, {
|
||||
"url": "http://nova/novapi/internal",
|
||||
"region": "RegionOne",
|
||||
"interface": "internal"
|
||||
}, {
|
||||
"url": "http://nova/novapi/admin",
|
||||
"region": "RegionOne",
|
||||
"interface": "admin"
|
||||
}],
|
||||
"type": "compute"
|
||||
}, {
|
||||
"endpoints": [{
|
||||
"url": "http://glance/glanceapi/public",
|
||||
"region": "RegionOne",
|
||||
"interface": "public"
|
||||
}, {
|
||||
"url": "http://glance/glanceapi/internal",
|
||||
"region": "RegionOne",
|
||||
"interface": "internal"
|
||||
}, {
|
||||
"url": "http://glance/glanceapi/admin",
|
||||
"region": "RegionOne",
|
||||
"interface": "admin"
|
||||
}],
|
||||
"type": "image",
|
||||
"name": "glance"
|
||||
}, {
|
||||
"endpoints": [{
|
||||
"url": "http://127.0.0.1:5000/v3",
|
||||
"region": "RegionOne",
|
||||
"interface": "public"
|
||||
}, {
|
||||
"url": "http://127.0.0.1:5000/v3",
|
||||
"region": "RegionOne",
|
||||
"interface": "internal"
|
||||
}, {
|
||||
"url": TEST_ADMIN_URL,
|
||||
"region": "RegionOne",
|
||||
"interface": "admin"
|
||||
}],
|
||||
"type": "identity"
|
||||
}, {
|
||||
"endpoints": [{
|
||||
"url": "http://swift/swiftapi/public",
|
||||
"region": "RegionOne",
|
||||
"interface": "public"
|
||||
}, {
|
||||
"url": "http://swift/swiftapi/internal",
|
||||
"region": "RegionOne",
|
||||
"interface": "internal"
|
||||
}, {
|
||||
"url": "http://swift/swiftapi/admin",
|
||||
"region": "RegionOne",
|
||||
"interface": "admin"
|
||||
}],
|
||||
"type": "object-store"
|
||||
}]
|
||||
|
||||
def setUp(self):
|
||||
super(V3IdentityPlugin, self).setUp()
|
||||
@@ -232,3 +309,55 @@ class V3IdentityPlugin(utils.TestCase):
|
||||
username=self.TEST_USER, password=self.TEST_PASS,
|
||||
domain_id='x', trust_id='x')
|
||||
self.assertRaises(exceptions.AuthorizationFailure, a.get_auth_ref, s)
|
||||
|
||||
@httpretty.activate
|
||||
def _do_service_url_test(self, base_url, endpoint_filter):
|
||||
self.stub_auth(json=self.TEST_RESPONSE_DICT)
|
||||
self.stub_url(httpretty.GET, ['path'],
|
||||
base_url=base_url,
|
||||
body='SUCCESS', status=200)
|
||||
|
||||
a = v3.Password(self.TEST_URL, username=self.TEST_USER,
|
||||
password=self.TEST_PASS)
|
||||
s = session.Session(auth=a)
|
||||
|
||||
resp = s.get('/path', endpoint_filter=endpoint_filter)
|
||||
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
path = "%s/%s" % (urllib.parse.urlparse(base_url).path, 'path')
|
||||
self.assertEqual(httpretty.last_request().path, path)
|
||||
|
||||
def test_service_url(self):
|
||||
endpoint_filter = {'service_type': 'compute', 'interface': 'admin'}
|
||||
self._do_service_url_test('http://nova/novapi/admin', endpoint_filter)
|
||||
|
||||
def test_service_url_defaults_to_public(self):
|
||||
endpoint_filter = {'service_type': 'compute'}
|
||||
self._do_service_url_test('http://nova/novapi/public', endpoint_filter)
|
||||
|
||||
@httpretty.activate
|
||||
def test_endpoint_filter_without_service_type_fails(self):
|
||||
self.stub_auth(json=self.TEST_RESPONSE_DICT)
|
||||
|
||||
a = v3.Password(self.TEST_URL, username=self.TEST_USER,
|
||||
password=self.TEST_PASS)
|
||||
s = session.Session(auth=a)
|
||||
|
||||
self.assertRaises(exceptions.EndpointNotFound, s.get, '/path',
|
||||
endpoint_filter={'interface': 'admin'})
|
||||
|
||||
@httpretty.activate
|
||||
def test_full_url_overrides_endpoint_filter(self):
|
||||
self.stub_auth(json=self.TEST_RESPONSE_DICT)
|
||||
self.stub_url(httpretty.GET, [],
|
||||
base_url='http://testurl/',
|
||||
body='SUCCESS', status=200)
|
||||
|
||||
a = v3.Password(self.TEST_URL, username=self.TEST_USER,
|
||||
password=self.TEST_PASS)
|
||||
s = session.Session(auth=a)
|
||||
|
||||
resp = s.get('http://testurl/',
|
||||
endpoint_filter={'service_type': 'compute'})
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertEqual(resp.text, 'SUCCESS')
|
||||
|
@@ -281,18 +281,41 @@ class AuthPlugin(base.BaseAuthPlugin):
|
||||
|
||||
TEST_TOKEN = 'aToken'
|
||||
|
||||
SERVICE_URLS = {
|
||||
'identity': {'public': 'http://identity-public:1111/v2.0',
|
||||
'admin': 'http://identity-admin:1111/v2.0'},
|
||||
'compute': {'public': 'http://compute-public:2222/v1.0',
|
||||
'admin': 'http://compute-admin:2222/v1.0'},
|
||||
'image': {'public': 'http://image-public:3333/v2.0',
|
||||
'admin': 'http://image-admin:3333/v2.0'}
|
||||
}
|
||||
|
||||
def __init__(self, token=TEST_TOKEN):
|
||||
self.token = token
|
||||
|
||||
def get_token(self, session):
|
||||
return self.token
|
||||
|
||||
def get_endpoint(self, session, service_type=None, interface=None,
|
||||
**kwargs):
|
||||
try:
|
||||
return self.SERVICE_URLS[service_type][interface]
|
||||
except (KeyError, AttributeError):
|
||||
return None
|
||||
|
||||
|
||||
class SessionAuthTests(utils.TestCase):
|
||||
|
||||
TEST_URL = 'http://127.0.0.1:5000/'
|
||||
TEST_JSON = {'hello': 'world'}
|
||||
|
||||
def stub_service_url(self, service_type, interface, path,
|
||||
method=httpretty.GET, **kwargs):
|
||||
base_url = AuthPlugin.SERVICE_URLS[service_type][interface]
|
||||
uri = "%s/%s" % (base_url.rstrip('/'), path.lstrip('/'))
|
||||
|
||||
httpretty.register_uri(method, uri, **kwargs)
|
||||
|
||||
@httpretty.activate
|
||||
def test_auth_plugin_default_with_plugin(self):
|
||||
self.stub_url('GET', base_url=self.TEST_URL, json=self.TEST_JSON)
|
||||
@@ -315,3 +338,40 @@ class SessionAuthTests(utils.TestCase):
|
||||
self.assertDictEqual(resp.json(), self.TEST_JSON)
|
||||
|
||||
self.assertRequestHeaderEqual('X-Auth-Token', None)
|
||||
|
||||
@httpretty.activate
|
||||
def test_service_type_urls(self):
|
||||
service_type = 'compute'
|
||||
interface = 'public'
|
||||
path = '/instances'
|
||||
status = 200
|
||||
body = 'SUCCESS'
|
||||
|
||||
self.stub_service_url(service_type=service_type,
|
||||
interface=interface,
|
||||
path=path,
|
||||
status=status,
|
||||
body=body)
|
||||
|
||||
sess = client_session.Session(auth=AuthPlugin())
|
||||
resp = sess.get(path,
|
||||
endpoint_filter={'service_type': service_type,
|
||||
'interface': interface})
|
||||
|
||||
self.assertEqual(httpretty.last_request().path, '/v1.0/instances')
|
||||
self.assertEqual(resp.text, body)
|
||||
self.assertEqual(resp.status_code, status)
|
||||
|
||||
def test_service_url_raises_if_no_auth_plugin(self):
|
||||
sess = client_session.Session()
|
||||
self.assertRaises(exceptions.MissingAuthPlugin,
|
||||
sess.get, '/path',
|
||||
endpoint_filter={'service_type': 'compute',
|
||||
'interface': 'public'})
|
||||
|
||||
def test_service_url_raises_if_no_url_returned(self):
|
||||
sess = client_session.Session(auth=AuthPlugin())
|
||||
self.assertRaises(exceptions.EndpointNotFound,
|
||||
sess.get, '/path',
|
||||
endpoint_filter={'service_type': 'unknown',
|
||||
'interface': 'public'})
|
||||
|
@@ -171,6 +171,9 @@ class Client(httpclient.HTTPClient):
|
||||
except (exceptions.AuthorizationFailure, exceptions.Unauthorized):
|
||||
_logger.debug("Authorization Failed.")
|
||||
raise
|
||||
except exceptions.EndpointNotFound:
|
||||
msg = 'There was no suitable authentication url for this request'
|
||||
raise exceptions.AuthorizationFailure(msg)
|
||||
except Exception as e:
|
||||
raise exceptions.AuthorizationFailure("Authorization Failed: "
|
||||
"%s" % e)
|
||||
|
@@ -168,6 +168,9 @@ class Client(httpclient.HTTPClient):
|
||||
except (exceptions.AuthorizationFailure, exceptions.Unauthorized):
|
||||
_logger.debug('Authorization failed.')
|
||||
raise
|
||||
except exceptions.EndpointNotFound:
|
||||
msg = 'There was no suitable authentication url for this request'
|
||||
raise exceptions.AuthorizationFailure(msg)
|
||||
except Exception as e:
|
||||
raise exceptions.AuthorizationFailure('Authorization failed: '
|
||||
'%s' % e)
|
||||
|
Reference in New Issue
Block a user