From 5b8b04a2133cbaad84bf7d4bb58801c28f66a938 Mon Sep 17 00:00:00 2001 From: Liam Young Date: Fri, 16 Sep 2016 13:53:13 +0000 Subject: [PATCH] Fix support for Keystone v3 API Swift proxy is currently rejecting valid v3 tokens because it is failing to validate them due to its credentials being in the v2 format and missing domain information. This change examines the version of the API keystone has advertised down the identity-service relation and configures the proxy conf appropriately Change-Id: Id2215168ffbad1caf0e7203ded26c41913181306 Closes-Bug: 1624304 --- lib/swift_context.py | 9 +++- templates/kilo/proxy-server.conf | 10 +++++ unit_tests/test_swift_context.py | 72 ++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) diff --git a/lib/swift_context.py b/lib/swift_context.py index 3132b15..4d07fa9 100644 --- a/lib/swift_context.py +++ b/lib/swift_context.py @@ -139,7 +139,7 @@ class SwiftIdentityContext(OSContextGenerator): 'auth_port': config('keystone-auth-port'), 'service_user': admin_user, 'service_password': admin_password, - 'service_tenant': config('keystone-admin-tenant-name') + 'service_tenant': config('keystone-admin-tenant-name'), } ctxt.update(ks_auth) @@ -168,7 +168,14 @@ class SwiftIdentityContext(OSContextGenerator): unit, relid), 'admin_token': relation_get('admin_token', unit, relid), + 'api_version': relation_get('api_version', + unit, relid) or '2', } + if ks_auth['api_version'] == '3': + ks_auth['admin_domain_id'] = relation_get( + 'admin_domain_id', unit, relid) + ks_auth['service_tenant_id'] = relation_get( + 'service_tenant_id', unit, relid) if context_complete(ks_auth): ctxt.update(ks_auth) diff --git a/templates/kilo/proxy-server.conf b/templates/kilo/proxy-server.conf index 0c0bf13..443f9e0 100644 --- a/templates/kilo/proxy-server.conf +++ b/templates/kilo/proxy-server.conf @@ -82,9 +82,19 @@ operator_roles = {{ operator_roles }} paste.filter_factory = keystonemiddleware.auth_token:filter_factory identity_uri = {{ auth_protocol }}://{{ keystone_host }}:{{ auth_port }} auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }} +{% if api_version == '3' -%} +auth_plugin = password +auth_url = {{ auth_protocol }}://{{ keystone_host }}:{{ auth_port }} +username = {{ service_user }} +password = {{ service_password }} +user_domain_name = default +project_id = {{ service_tenant_id }} +project_domain_id = {{ admin_domain_id }} +{% else -%} admin_tenant_name = {{ service_tenant }} admin_user = {{ service_user }} admin_password = {{ service_password }} +{% endif -%} delay_auth_decision = {{ delay_auth_decision|lower }} signing_dir = {{ signing_dir }} cache = swift.cache diff --git a/unit_tests/test_swift_context.py b/unit_tests/test_swift_context.py index 2e4e503..0d6ae7a 100644 --- a/unit_tests/test_swift_context.py +++ b/unit_tests/test_swift_context.py @@ -23,6 +23,78 @@ with mock.patch('charmhelpers.core.hookenv.config'): import lib.swift_context as swift_context +class SwiftIdentityContextTest(unittest.TestCase): + + @mock.patch('lib.swift_context.relation_get') + @mock.patch('lib.swift_context.related_units') + @mock.patch('lib.swift_context.relation_ids') + @mock.patch('lib.swift_context.IdentityServiceContext') + @mock.patch('lib.swift_context.determine_api_port') + @mock.patch('lib.swift_context.unit_get') + @mock.patch('lib.swift_context.get_host_ip') + @mock.patch('lib.swift_context.config') + def test_context_api_v2(self, mock_config, mock_get_host_ip, + mock_unit_get, mock_determine_api_port, + mock_IdentityServiceContext, mock_relation_ids, + mock_related_units, mock_relation_get): + _relinfo = { + 'auth_protocol': 'http', + 'service_protocol': 'http', + 'auth_host': 'kshost', + 'service_host': 'kshost', + 'auth_port': '5000', + 'service_username': 'svcuser', + 'service_password': 'svcpasswd', + 'service_tenant': 'svctenant', + 'service_port': 'svcport', + 'admin_token': 'token', + 'api_version': None, + } + mock_config.return_value = None + mock_relation_ids.return_value = ['rid1'] + mock_related_units.return_value = ['ksunit/0'] + mock_relation_get.side_effect = lambda x, y, z: _relinfo[x] + ctxt = swift_context.SwiftIdentityContext() + self.assertEqual(ctxt()['api_version'], '2') + + @mock.patch('lib.swift_context.relation_get') + @mock.patch('lib.swift_context.related_units') + @mock.patch('lib.swift_context.relation_ids') + @mock.patch('lib.swift_context.IdentityServiceContext') + @mock.patch('lib.swift_context.determine_api_port') + @mock.patch('lib.swift_context.unit_get') + @mock.patch('lib.swift_context.get_host_ip') + @mock.patch('lib.swift_context.config') + def test_context_api_v3(self, mock_config, mock_get_host_ip, + mock_unit_get, mock_determine_api_port, + mock_IdentityServiceContext, mock_relation_ids, + mock_related_units, mock_relation_get): + _relinfo = { + 'auth_protocol': 'http', + 'service_protocol': 'http', + 'auth_host': 'kshost', + 'service_host': 'kshost', + 'auth_port': '5000', + 'service_username': 'svcuser', + 'service_password': 'svcpasswd', + 'service_tenant': 'svctenant', + 'service_port': 'svcport', + 'admin_token': 'token', + 'api_version': '3', + 'admin_domain_id': 'admin_dom_id', + 'service_tenant_id': 'svc_tenant_id', + } + self.maxDiff = None + mock_relation_ids.return_value = ['rid1'] + mock_related_units.return_value = ['ksunit/0'] + mock_relation_get.side_effect = lambda x, y, z: _relinfo[x] + mock_config.return_value = None + ctxt = swift_context.SwiftIdentityContext() + self.assertEqual(ctxt()['api_version'], '3') + self.assertEqual(ctxt()['admin_domain_id'], 'admin_dom_id') + self.assertEqual(ctxt()['service_tenant_id'], 'svc_tenant_id') + + class SwiftContextTestCase(unittest.TestCase): @mock.patch('lib.swift_context.config')