summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Fedosin <mfedosin@mirantis.com>2015-11-27 18:25:01 +0300
committerkairat_kushaev <kkushaev@mirantis.com>2016-01-19 13:38:20 +0300
commit3331ac6b4c86a73a060cf9a613537d364ac4bbb3 (patch)
tree7067c2a93c3cdf43358870c8c812eb7a4be4b541
parente983e894d4fb6d03e1d54529da532db436c012a1 (diff)
downloadglance_store-3331ac6b4c86a73a060cf9a613537d364ac4bbb3.tar.gz
Remove unnecessary auth module
This commit removes common/auth.py file and changes the way how endpoint for MultiTenant store is found. Without having custom implementation it's better to use an unified method 'url_for' that service_catalog provides. Co-Authored-By: kairat_kushaev <kkushaev@mirantis.com> Change-Id: If8d07e378140a940317db1259a58477d7809948e
-rw-r--r--glance_store/_drivers/swift/store.py8
-rw-r--r--glance_store/common/auth.py293
-rw-r--r--glance_store/tests/unit/test_swift_store.py72
3 files changed, 44 insertions, 329 deletions
diff --git a/glance_store/_drivers/swift/store.py b/glance_store/_drivers/swift/store.py
index 591b16d..603a435 100644
--- a/glance_store/_drivers/swift/store.py
+++ b/glance_store/_drivers/swift/store.py
@@ -33,7 +33,6 @@ except ImportError:
import glance_store
from glance_store._drivers.swift import utils as sutils
from glance_store import capabilities
-from glance_store.common import auth
from glance_store.common import utils as cutils
from glance_store import driver
from glance_store import exceptions
@@ -870,9 +869,10 @@ class MultiTenantStore(BaseStore):
reason=reason)
self.storage_url = self.conf_endpoint
if not self.storage_url:
- self.storage_url = auth.get_endpoint(
- context.service_catalog, service_type=self.service_type,
- endpoint_region=self.region, endpoint_type=self.endpoint_type)
+
+ self.storage_url = context.service_catalog.url_for(
+ service_type=self.service_type, region_name=self.region,
+ endpoint_type=self.endpoint_type)
if self.storage_url.startswith('http://'):
self.scheme = 'swift+http'
diff --git a/glance_store/common/auth.py b/glance_store/common/auth.py
deleted file mode 100644
index b5fa06e..0000000
--- a/glance_store/common/auth.py
+++ /dev/null
@@ -1,293 +0,0 @@
-# Copyright 2011 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-"""
-This auth module is intended to allow OpenStack client-tools to select from a
-variety of authentication strategies, including NoAuth (the default), and
-Keystone (an identity management system).
-
- > auth_plugin = AuthPlugin(creds)
-
- > auth_plugin.authenticate()
-
- > auth_plugin.auth_token
- abcdefg
-
- > auth_plugin.management_url
- http://service_endpoint/
-"""
-import httplib2
-import logging
-
-from oslo_serialization import jsonutils
-# NOTE(jokke): simplified transition to py3, behaves like py2 xrange
-from six.moves import range
-from six.moves import urllib
-
-from glance_store import exceptions
-from glance_store.i18n import _
-
-
-LOG = logging.getLogger(__name__)
-
-
-class BaseStrategy(object):
- def __init__(self):
- self.auth_token = None
- # TODO(sirp): Should expose selecting public/internal/admin URL.
- self.management_url = None
-
- def authenticate(self):
- raise NotImplementedError
-
- @property
- def is_authenticated(self):
- raise NotImplementedError
-
- @property
- def strategy(self):
- raise NotImplementedError
-
-
-class NoAuthStrategy(BaseStrategy):
- def authenticate(self):
- pass
-
- @property
- def is_authenticated(self):
- return True
-
- @property
- def strategy(self):
- return 'noauth'
-
-
-class KeystoneStrategy(BaseStrategy):
- MAX_REDIRECTS = 10
-
- def __init__(self, creds, insecure=False, configure_via_auth=True):
- self.creds = creds
- self.insecure = insecure
- self.configure_via_auth = configure_via_auth
- super(KeystoneStrategy, self).__init__()
-
- def check_auth_params(self):
- # Ensure that supplied credential parameters are as required
- for required in ('username', 'password', 'auth_url',
- 'strategy'):
- if self.creds.get(required) is None:
- raise exceptions.MissingCredentialError(required=required)
- if self.creds['strategy'] != 'keystone':
- raise exceptions.BadAuthStrategy(expected='keystone',
- received=self.creds['strategy'])
- # For v2.0 also check tenant is present
- if self.creds['auth_url'].rstrip('/').endswith('v2.0'):
- if self.creds.get("tenant") is None:
- raise exceptions.MissingCredentialError(required='tenant')
-
- def authenticate(self):
- """Authenticate with the Keystone service.
-
- There are a few scenarios to consider here:
-
- 1. Which version of Keystone are we using? v1 which uses headers to
- pass the credentials, or v2 which uses a JSON encoded request body?
-
- 2. Keystone may respond back with a redirection using a 305 status
- code.
-
- 3. We may attempt a v1 auth when v2 is what's called for. In this
- case, we rewrite the url to contain /v2.0/ and retry using the v2
- protocol.
- """
- def _authenticate(auth_url):
- # If OS_AUTH_URL is missing a trailing slash add one
- if not auth_url.endswith('/'):
- auth_url += '/'
- token_url = urllib.parse.urljoin(auth_url, "tokens")
- # 1. Check Keystone version
- is_v2 = auth_url.rstrip('/').endswith('v2.0')
- if is_v2:
- self._v2_auth(token_url)
- else:
- self._v1_auth(token_url)
-
- self.check_auth_params()
- auth_url = self.creds['auth_url']
- for __ in range(self.MAX_REDIRECTS):
- try:
- _authenticate(auth_url)
- except exceptions.AuthorizationRedirect as e:
- # 2. Keystone may redirect us
- auth_url = e.url
- except exceptions.AuthorizationFailure:
- # 3. In some configurations nova makes redirection to
- # v2.0 keystone endpoint. Also, new location does not
- # contain real endpoint, only hostname and port.
- if 'v2.0' not in auth_url:
- auth_url = urllib.parse.urljoin(auth_url, 'v2.0/')
- else:
- # If we successfully auth'd, then memorize the correct auth_url
- # for future use.
- self.creds['auth_url'] = auth_url
- break
- else:
- # Guard against a redirection loop
- raise exceptions.MaxRedirectsExceeded(redirects=self.MAX_REDIRECTS)
-
- def _v1_auth(self, token_url):
- creds = self.creds
-
- headers = {}
- headers['X-Auth-User'] = creds['username']
- headers['X-Auth-Key'] = creds['password']
-
- tenant = creds.get('tenant')
- if tenant:
- headers['X-Auth-Tenant'] = tenant
-
- resp, resp_body = self._do_request(token_url, 'GET', headers=headers)
-
- def _management_url(self, resp):
- for url_header in ('x-image-management-url',
- 'x-server-management-url',
- 'x-glance'):
- try:
- return resp[url_header]
- except KeyError as e:
- not_found = e
- raise not_found
-
- if resp.status in (200, 204):
- try:
- if self.configure_via_auth:
- self.management_url = _management_url(self, resp)
- self.auth_token = resp['x-auth-token']
- except KeyError:
- raise exceptions.AuthorizationFailure()
- elif resp.status == 305:
- raise exceptions.AuthorizationRedirect(uri=resp['location'])
- elif resp.status == 400:
- raise exceptions.AuthBadRequest(url=token_url)
- elif resp.status == 401:
- raise exceptions.NotAuthenticated()
- elif resp.status == 404:
- raise exceptions.AuthUrlNotFound(url=token_url)
- else:
- raise Exception(_('Unexpected response: %s') % resp.status)
-
- def _v2_auth(self, token_url):
-
- creds = self.creds
-
- creds = {
- "auth": {
- "tenantName": creds['tenant'],
- "passwordCredentials": {
- "username": creds['username'],
- "password": creds['password']
- }
- }
- }
-
- headers = {}
- headers['Content-Type'] = 'application/json'
- req_body = jsonutils.dumps(creds)
-
- resp, resp_body = self._do_request(
- token_url, 'POST', headers=headers, body=req_body)
-
- if resp.status == 200:
- resp_auth = jsonutils.loads(resp_body)['access']
- creds_region = self.creds.get('region')
- if self.configure_via_auth:
- endpoint = get_endpoint(resp_auth['serviceCatalog'],
- endpoint_region=creds_region)
- self.management_url = endpoint
- self.auth_token = resp_auth['token']['id']
- elif resp.status == 305:
- raise exceptions.RedirectException(resp['location'])
- elif resp.status == 400:
- raise exceptions.AuthBadRequest(url=token_url)
- elif resp.status == 401:
- raise exceptions.NotAuthenticated()
- elif resp.status == 404:
- raise exceptions.AuthUrlNotFound(url=token_url)
- else:
- raise Exception(_('Unexpected response: %s') % resp.status)
-
- @property
- def is_authenticated(self):
- return self.auth_token is not None
-
- @property
- def strategy(self):
- return 'keystone'
-
- def _do_request(self, url, method, headers=None, body=None):
- headers = headers or {}
- conn = httplib2.Http()
- conn.force_exception_to_status_code = True
- conn.disable_ssl_certificate_validation = self.insecure
- headers['User-Agent'] = 'glance-client'
- resp, resp_body = conn.request(url, method, headers=headers, body=body)
- return resp, resp_body
-
-
-def get_plugin_from_strategy(strategy, creds=None, insecure=False,
- configure_via_auth=True):
- if strategy == 'noauth':
- return NoAuthStrategy()
- elif strategy == 'keystone':
- return KeystoneStrategy(creds, insecure,
- configure_via_auth=configure_via_auth)
- else:
- raise Exception(_("Unknown auth strategy '%s'") % strategy)
-
-
-def get_endpoint(service_catalog, service_type='image', endpoint_region=None,
- endpoint_type='publicURL'):
- """
- Select an endpoint from the service catalog
-
- We search the full service catalog for services
- matching both type and region. If the client
- supplied no region then any 'image' endpoint
- is considered a match. There must be one -- and
- only one -- successful match in the catalog,
- otherwise we will raise an exception.
- """
- endpoint = None
- for service in service_catalog:
- s_type = None
- try:
- s_type = service['type']
- except KeyError:
- msg = _('Encountered service with no "type": %s') % s_type
- LOG.warn(msg)
- continue
-
- if s_type == service_type:
- for ep in service['endpoints']:
- if endpoint_region is None or endpoint_region == ep['region']:
- if endpoint is not None:
- # This is a second match, abort
- exc = exceptions.RegionAmbiguity
- raise exc(region=endpoint_region)
- endpoint = ep
- if endpoint and endpoint.get(endpoint_type):
- return endpoint[endpoint_type]
- else:
- raise exceptions.NoServiceEndpoint()
diff --git a/glance_store/tests/unit/test_swift_store.py b/glance_store/tests/unit/test_swift_store.py
index b749cce..f1f8769 100644
--- a/glance_store/tests/unit/test_swift_store.py
+++ b/glance_store/tests/unit/test_swift_store.py
@@ -37,7 +37,6 @@ from glance_store._drivers.swift import store as swift
from glance_store import backend
from glance_store import BackendException
from glance_store import capabilities
-from glance_store.common import auth
from glance_store.common import utils
from glance_store import exceptions
from glance_store import location
@@ -624,11 +623,11 @@ class SwiftTests(object):
self.config(swift_store_container='container')
self.config(swift_store_create_container_on_put=True)
self.config(swift_store_multiple_containers_seed=2)
- fake_get_endpoint = FakeGetEndpoint('https://some_endpoint')
- self.stubs.Set(auth, 'get_endpoint', fake_get_endpoint)
+ service_catalog = mock.MagicMock()
+ service_catalog.url_for.return_value = 'https://some_endpoint'
ctxt = mock.MagicMock(
user='user', tenant='tenant', auth_token='123',
- service_catalog={})
+ service_catalog=service_catalog)
store = swift.MultiTenantStore(self.conf)
store.configure()
location, size, checksum, _ = store.add(expected_image_id, image_swift,
@@ -1298,15 +1297,8 @@ class TestMultiTenantStoreContext(base.StoreBaseTest):
self.config(**conf)
self.store.configure()
self.register_store_schemes(self.store, 'swift')
- self.service_catalog = [{
- "name": "Object Storage",
- "type": "object-store",
- "endpoints": [{
- "publicURL": "http://127.0.0.1:0",
- "region": "region1",
- "versionId": "1.0",
- }]
- }]
+ self.service_catalog = mock.MagicMock()
+ self.service_catalog.url_for.return_value = "http://127.0.0.1:0"
self.addCleanup(self.conf.reset)
@requests_mock.mock()
@@ -1411,11 +1403,11 @@ class TestCreatingLocations(base.StoreBaseTest):
def test_multi_tenant_location(self):
self.config(swift_store_container='container')
- fake_get_endpoint = FakeGetEndpoint('https://some_endpoint')
- self.stubs.Set(auth, 'get_endpoint', fake_get_endpoint)
+ service_catalog = mock.MagicMock()
+ service_catalog.url_for.return_value = 'https://some_endpoint'
ctxt = mock.MagicMock(
user='user', tenant='tenant', auth_token='123',
- service_catalog={})
+ service_catalog=service_catalog)
store = swift.MultiTenantStore(self.conf)
store.configure()
location = store.create_location('image-id', context=ctxt)
@@ -1425,55 +1417,71 @@ class TestCreatingLocations(base.StoreBaseTest):
self.assertEqual(location.obj, 'image-id')
self.assertIsNone(location.user)
self.assertIsNone(location.key)
- self.assertEqual(fake_get_endpoint.service_type, 'object-store')
+ service_catalog.url_for.assert_called_once_with(
+ service_type=store.service_type,
+ region_name=store.region,
+ endpoint_type=store.endpoint_type)
def test_multi_tenant_location_http(self):
- fake_get_endpoint = FakeGetEndpoint('http://some_endpoint')
- self.stubs.Set(auth, 'get_endpoint', fake_get_endpoint)
+ service_catalog = mock.MagicMock()
+ service_catalog.url_for.return_value = 'http://some_endpoint'
ctxt = mock.MagicMock(
user='user', tenant='tenant', auth_token='123',
- service_catalog={})
+ service_catalog=service_catalog)
store = swift.MultiTenantStore(self.conf)
store.configure()
location = store.create_location('image-id', context=ctxt)
self.assertEqual(location.scheme, 'swift+http')
self.assertEqual(location.swift_url, 'http://some_endpoint')
+ service_catalog.url_for.assert_called_once_with(
+ service_type=store.service_type,
+ region_name=store.region,
+ endpoint_type=store.endpoint_type)
def test_multi_tenant_location_with_region(self):
self.config(swift_store_region='WestCarolina')
- fake_get_endpoint = FakeGetEndpoint('https://some_endpoint')
- self.stubs.Set(auth, 'get_endpoint', fake_get_endpoint)
+ service_catalog = mock.MagicMock()
+ service_catalog.url_for.return_value = 'https://some_endpoint'
ctxt = mock.MagicMock(
user='user', tenant='tenant', auth_token='123',
- service_catalog={})
+ service_catalog=service_catalog)
store = swift.MultiTenantStore(self.conf)
store.configure()
store._get_endpoint(ctxt)
- self.assertEqual(fake_get_endpoint.endpoint_region, 'WestCarolina')
+ service_catalog.url_for.assert_called_once_with(
+ service_type=store.service_type,
+ region_name=store.region,
+ endpoint_type=store.endpoint_type)
def test_multi_tenant_location_custom_service_type(self):
self.config(swift_store_service_type='toy-store')
- fake_get_endpoint = FakeGetEndpoint('https://some_endpoint')
- self.stubs.Set(auth, 'get_endpoint', fake_get_endpoint)
+ service_catalog = mock.MagicMock()
+ service_catalog.url_for.return_value = 'https://some_endpoint'
ctxt = mock.MagicMock(
user='user', tenant='tenant', auth_token='123',
- service_catalog={})
+ service_catalog=service_catalog)
store = swift.MultiTenantStore(self.conf)
store.configure()
store._get_endpoint(ctxt)
- self.assertEqual(fake_get_endpoint.service_type, 'toy-store')
+ service_catalog.url_for.assert_called_once_with(
+ service_type=store.service_type,
+ region_name=store.region,
+ endpoint_type=store.endpoint_type)
def test_multi_tenant_location_custom_endpoint_type(self):
self.config(swift_store_endpoint_type='InternalURL')
- fake_get_endpoint = FakeGetEndpoint('https://some_endpoint')
- self.stubs.Set(auth, 'get_endpoint', fake_get_endpoint)
+ service_catalog = mock.MagicMock()
+ service_catalog.url_for.return_value = 'https://some_endpoint'
ctxt = mock.MagicMock(
user='user', tenant='tenant', auth_token='123',
- service_catalog={})
+ service_catalog=service_catalog)
store = swift.MultiTenantStore(self.conf)
store.configure()
store._get_endpoint(ctxt)
- self.assertEqual(fake_get_endpoint.endpoint_type, 'InternalURL')
+ service_catalog.url_for.assert_called_once_with(
+ service_type=store.service_type,
+ region_name=store.region,
+ endpoint_type=store.endpoint_type)
class TestChunkReader(base.StoreBaseTest):