Merge "Handle URLs via the session and auth_plugins"
This commit is contained in:
@@ -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.
|
||||
"""
|
||||
|
@@ -89,3 +89,37 @@ class BaseIdentityPlugin(base.BaseAuthPlugin):
|
||||
self.auth_ref = self.get_auth_ref(session)
|
||||
|
||||
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)
|
||||
|
@@ -252,6 +252,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.
|
||||
@@ -558,25 +564,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
|
||||
@@ -113,7 +114,7 @@ class Session(object):
|
||||
@utils.positional(enforcement=utils.positional.WARN)
|
||||
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
|
||||
@@ -122,7 +123,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)
|
||||
@@ -139,6 +144,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.
|
||||
@@ -164,6 +174,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)
|
||||
|
||||
@@ -347,3 +370,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