Support V3 authentication with swift
This is the easiest way to support v3 authentication in the swift backend. It allows us to specify that we want v3 authentication and provide the extra authentication attributes to swiftclient. It allows specifying auth_version via individual authentication references so that you can mix v2 and v3 authentication. Ideally in future we would move to a session orientated solution. In which case we will need to handle the existing options in a backwards compatible way and so I don't think that the extra arguments will cause any additional problems there. Change-Id: Ifb7c9be805689e938ff0e99a18fa220993862001
This commit is contained in:
parent
cd04b9217f
commit
b529f0a782
@ -48,10 +48,6 @@ DEFAULT_LARGE_OBJECT_CHUNK_SIZE = 200 # 200M
|
||||
ONE_MB = units.k * units.Ki # Here we used the mixed meaning of MB
|
||||
|
||||
_SWIFT_OPTS = [
|
||||
cfg.StrOpt('swift_store_auth_version', default='2',
|
||||
help=_('Version of the authentication service to use. '
|
||||
'Valid versions are 2 for keystone and 1 for swauth '
|
||||
'and rackspace. (deprecated)')),
|
||||
cfg.BoolOpt('swift_store_auth_insecure', default=False,
|
||||
help=_('If True, swiftclient won\'t check for a valid SSL '
|
||||
'certificate when authenticating.')),
|
||||
@ -728,8 +724,14 @@ class SingleTenantStore(BaseStore):
|
||||
self.ref_params = sutils.SwiftParams(self.conf).params
|
||||
|
||||
def configure(self, re_raise_bsc=False):
|
||||
super(SingleTenantStore, self).configure(re_raise_bsc=re_raise_bsc)
|
||||
# set configuration before super so configure_add can override
|
||||
self.auth_version = self._option_get('swift_store_auth_version')
|
||||
self.user_domain_id = None
|
||||
self.user_domain_name = None
|
||||
self.project_domain_id = None
|
||||
self.project_domain_name = None
|
||||
|
||||
super(SingleTenantStore, self).configure(re_raise_bsc=re_raise_bsc)
|
||||
|
||||
def configure_add(self):
|
||||
default_ref = self.conf.glance_store.default_swift_reference
|
||||
@ -746,8 +748,15 @@ class SingleTenantStore(BaseStore):
|
||||
else:
|
||||
self.scheme = 'swift+https'
|
||||
self.container = self.conf.glance_store.swift_store_container
|
||||
self.auth_version = default_swift_reference.get('auth_version')
|
||||
self.user = default_swift_reference.get('user')
|
||||
self.key = default_swift_reference.get('key')
|
||||
self.user_domain_id = default_swift_reference.get('user_domain_id')
|
||||
self.user_domain_name = default_swift_reference.get('user_domain_name')
|
||||
self.project_domain_id = default_swift_reference.get(
|
||||
'project_domain_id')
|
||||
self.project_domain_name = default_swift_reference.get(
|
||||
'project_domain_name')
|
||||
|
||||
if not (self.user or self.key):
|
||||
reason = _("A value for swift_store_ref_params is required.")
|
||||
@ -811,7 +820,7 @@ class SingleTenantStore(BaseStore):
|
||||
if not auth_url.endswith('/'):
|
||||
auth_url += '/'
|
||||
|
||||
if self.auth_version == '2':
|
||||
if self.auth_version in ('2', '3'):
|
||||
try:
|
||||
tenant_name, user = location.user.split(':')
|
||||
except ValueError:
|
||||
@ -828,6 +837,14 @@ class SingleTenantStore(BaseStore):
|
||||
os_options['region_name'] = self.region
|
||||
os_options['endpoint_type'] = self.endpoint_type
|
||||
os_options['service_type'] = self.service_type
|
||||
if self.user_domain_id:
|
||||
os_options['user_domain_id'] = self.user_domain_id
|
||||
if self.user_domain_name:
|
||||
os_options['user_domain_name'] = self.user_domain_name
|
||||
if self.project_domain_id:
|
||||
os_options['project_domain_id'] = self.project_domain_id
|
||||
if self.project_domain_name:
|
||||
os_options['project_domain_name'] = self.project_domain_name
|
||||
|
||||
return swiftclient.Connection(
|
||||
auth_url, user, location.key, preauthurl=self.conf_endpoint,
|
||||
|
@ -27,23 +27,38 @@ swift_opts = [
|
||||
default="ref1",
|
||||
help=i18n._('The reference to the default swift account/backing'
|
||||
' store parameters to use for adding new images.')),
|
||||
cfg.StrOpt('swift_store_auth_version', default='2',
|
||||
help=i18n._('Version of the authentication service to use. '
|
||||
'Valid versions are 2 and 3 for keystone and 1 '
|
||||
'(deprecated) for swauth and rackspace. '
|
||||
'(deprecated - use "auth_version" in '
|
||||
'swift_store_config_file)')),
|
||||
cfg.StrOpt('swift_store_auth_address',
|
||||
help=i18n._('The address where the Swift authentication '
|
||||
'service is listening.(deprecated)')),
|
||||
'service is listening. (deprecated - use '
|
||||
'"auth_address" in swift_store_config_file)')),
|
||||
cfg.StrOpt('swift_store_user', secret=True,
|
||||
help=i18n._('The user to authenticate against the Swift '
|
||||
'authentication service (deprecated)')),
|
||||
'authentication service (deprecated - use "user" '
|
||||
'in swift_store_config_file)')),
|
||||
cfg.StrOpt('swift_store_key', secret=True,
|
||||
help=i18n._('Auth key for the user authenticating against the '
|
||||
'Swift authentication service. (deprecated)')),
|
||||
'Swift authentication service. (deprecated - use '
|
||||
'"key" in swift_store_config_file)')),
|
||||
cfg.StrOpt('swift_store_config_file', secret=True,
|
||||
help=i18n._('The config file that has the swift account(s)'
|
||||
'configs.')),
|
||||
]
|
||||
|
||||
_config_defaults = {'user_domain_id': None,
|
||||
'user_domain_name': None,
|
||||
'project_domain_id': None,
|
||||
'project_domain_name': None}
|
||||
|
||||
# NOTE(bourke): The default dict_type is collections.OrderedDict in py27, but
|
||||
# we must set manually for compatibility with py26
|
||||
CONFIG = configparser.SafeConfigParser(dict_type=OrderedDict)
|
||||
CONFIG = configparser.SafeConfigParser(defaults=_config_defaults,
|
||||
dict_type=OrderedDict)
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -74,6 +89,11 @@ class SwiftParams(object):
|
||||
default['user'] = glance_store.swift_store_user
|
||||
default['key'] = glance_store.swift_store_key
|
||||
default['auth_address'] = glance_store.swift_store_auth_address
|
||||
default['project_domain_id'] = None
|
||||
default['project_domain_name'] = None
|
||||
default['user_domain_id'] = None
|
||||
default['user_domain_name'] = None
|
||||
default['auth_version'] = glance_store.swift_store_auth_version
|
||||
return {glance_store.default_swift_reference: default}
|
||||
return {}
|
||||
|
||||
@ -92,12 +112,25 @@ class SwiftParams(object):
|
||||
reason=msg)
|
||||
account_params = {}
|
||||
account_references = CONFIG.sections()
|
||||
|
||||
for ref in account_references:
|
||||
reference = {}
|
||||
try:
|
||||
reference['auth_address'] = CONFIG.get(ref, 'auth_address')
|
||||
reference['user'] = CONFIG.get(ref, 'user')
|
||||
reference['key'] = CONFIG.get(ref, 'key')
|
||||
for param in ('auth_address',
|
||||
'user',
|
||||
'key',
|
||||
'project_domain_id',
|
||||
'project_domain_name',
|
||||
'user_domain_id',
|
||||
'user_domain_name'):
|
||||
reference[param] = CONFIG.get(ref, param)
|
||||
|
||||
try:
|
||||
reference['auth_version'] = CONFIG.get(ref, 'auth_version')
|
||||
except configparser.NoOptionError:
|
||||
av = self.conf.glance_store.swift_store_auth_version
|
||||
reference['auth_version'] = av
|
||||
|
||||
account_params[ref] = reference
|
||||
except (ValueError, SyntaxError, configparser.NoOptionError) as e:
|
||||
LOG.exception(i18n._("Invalid format of swift store config"
|
||||
|
@ -6,6 +6,9 @@ auth_address = example.com
|
||||
[ref2]
|
||||
user = user2
|
||||
key = key2
|
||||
user_domain_id = default
|
||||
project_domain_id = default
|
||||
auth_version = 3
|
||||
auth_address = http://example.com
|
||||
|
||||
[store_2]
|
||||
|
@ -1041,6 +1041,15 @@ class TestStoreAuthV2(TestStoreAuthV1):
|
||||
self.assertEqual('swift', loc.store_name)
|
||||
|
||||
|
||||
class TestStoreAuthV3(TestStoreAuthV1):
|
||||
|
||||
def getConfig(self):
|
||||
conf = super(TestStoreAuthV3, self).getConfig()
|
||||
conf['swift_store_auth_version'] = '3'
|
||||
conf['swift_store_user'] = 'tenant:user1'
|
||||
return conf
|
||||
|
||||
|
||||
class FakeConnection(object):
|
||||
def __init__(self, authurl, user, key, retries=5, preauthurl=None,
|
||||
preauthtoken=None, starting_backoff=1, tenant_name=None,
|
||||
@ -1202,6 +1211,52 @@ class TestSingleTenantStoreConnections(base.StoreBaseTest):
|
||||
self.location.parse_uri,
|
||||
self.location.uri)
|
||||
|
||||
def test_ref_overrides_defaults(self):
|
||||
self.config(swift_store_auth_version='2',
|
||||
swift_store_user='testuser',
|
||||
swift_store_key='testpass',
|
||||
swift_store_auth_address='testaddress',
|
||||
swift_store_endpoint_type='internalURL',
|
||||
swift_store_config_file='somefile')
|
||||
|
||||
self.store.ref_params = {'ref1': {'auth_address': 'authurl.com',
|
||||
'auth_version': '3',
|
||||
'user': 'user:pass',
|
||||
'user_domain_id': 'default',
|
||||
'user_domain_name': 'ignored',
|
||||
'project_domain_id': 'default',
|
||||
'project_domain_name': 'ignored'}}
|
||||
|
||||
self.store.configure()
|
||||
|
||||
self.assertEqual('user:pass', self.store.user)
|
||||
self.assertEqual('3', self.store.auth_version)
|
||||
self.assertEqual('authurl.com', self.store.auth_address)
|
||||
self.assertEqual('default', self.store.user_domain_id)
|
||||
self.assertEqual('ignored', self.store.user_domain_name)
|
||||
self.assertEqual('default', self.store.project_domain_id)
|
||||
self.assertEqual('ignored', self.store.project_domain_name)
|
||||
|
||||
def test_with_v3_auth(self):
|
||||
self.store.ref_params = {'ref1': {'auth_address': 'authurl.com',
|
||||
'auth_version': '3',
|
||||
'user': 'user:pass',
|
||||
'key': 'password',
|
||||
'user_domain_id': 'default',
|
||||
'user_domain_name': 'ignored',
|
||||
'project_domain_id': 'default',
|
||||
'project_domain_name': 'ignored'}}
|
||||
self.store.configure()
|
||||
connection = self.store.get_connection(self.location)
|
||||
self.assertEqual('3', connection.auth_version)
|
||||
self.assertEqual(connection.os_options,
|
||||
{'service_type': 'object-store',
|
||||
'endpoint_type': 'publicURL',
|
||||
'user_domain_id': 'default',
|
||||
'user_domain_name': 'ignored',
|
||||
'project_domain_id': 'default',
|
||||
'project_domain_name': 'ignored'})
|
||||
|
||||
|
||||
class TestMultiTenantStoreConnections(base.StoreBaseTest):
|
||||
def setUp(self):
|
||||
|
Loading…
Reference in New Issue
Block a user