diff --git a/doc/source/admin/configuration/service-user-token.rst b/doc/source/admin/configuration/service-user-token.rst index c5465bbbc9ad..58c9d0e30f62 100644 --- a/doc/source/admin/configuration/service-user-token.rst +++ b/doc/source/admin/configuration/service-user-token.rst @@ -37,7 +37,6 @@ configuration file, for example: [service_user] send_service_user_token = true auth_url = $AUTH_URL - auth_strategy = keystone auth_type = password project_domain_name = $PROJECT_DOMAIN_NAME project_name = service diff --git a/doc/source/admin/metadata-service.rst b/doc/source/admin/metadata-service.rst index 2b9f8f174312..addb69d2f6ff 100644 --- a/doc/source/admin/metadata-service.rst +++ b/doc/source/admin/metadata-service.rst @@ -101,8 +101,7 @@ following to a :file:`nova-api.conf` file: .. note:: This does not include configuration options that are not metadata-specific - but are nonetheless required, such as - :oslo.config:option:`api.auth_strategy`. + but are nonetheless required. Configuring the application to use the ``DynamicJSON`` vendordata provider is more involved and is not covered here. @@ -138,8 +137,7 @@ file: .. note:: This does not include configuration options that are not metadata-specific - but are nonetheless required, such as - :oslo.config:option:`api.auth_strategy`. + but are nonetheless required. For information about configuring the neutron side of the metadata service, refer to the :neutron-doc:`neutron configuration guide diff --git a/etc/nova/api-paste.ini b/etc/nova/api-paste.ini index b73a9fea3992..d0c38f23f146 100644 --- a/etc/nova/api-paste.ini +++ b/etc/nova/api-paste.ini @@ -31,16 +31,10 @@ use = call:nova.api.openstack.urlmap:urlmap_factory [composite:openstack_compute_api_v21] use = call:nova.api.auth:pipeline_factory_v21 keystone = cors http_proxy_to_wsgi compute_req_id faultwrap request_log sizelimit osprofiler authtoken keystonecontext osapi_compute_app_v21 -# DEPRECATED: The [api]auth_strategy conf option is deprecated and will be -# removed in a subsequent release, whereupon this pipeline will be unreachable. -noauth2 = cors http_proxy_to_wsgi compute_req_id faultwrap request_log sizelimit osprofiler noauth2 osapi_compute_app_v21 [composite:openstack_compute_api_v21_legacy_v2_compatible] use = call:nova.api.auth:pipeline_factory_v21 keystone = cors http_proxy_to_wsgi compute_req_id faultwrap request_log sizelimit osprofiler authtoken keystonecontext legacy_v2_compatible osapi_compute_app_v21 -# DEPRECATED: The [api]auth_strategy conf option is deprecated and will be -# removed in a subsequent release, whereupon this pipeline will be unreachable. -noauth2 = cors http_proxy_to_wsgi compute_req_id faultwrap request_log sizelimit osprofiler noauth2 legacy_v2_compatible osapi_compute_app_v21 [filter:request_log] paste.filter_factory = nova.api.openstack.requestlog:RequestLog.factory @@ -51,11 +45,6 @@ paste.filter_factory = nova.api.compute_req_id:ComputeReqIdMiddleware.factory [filter:faultwrap] paste.filter_factory = nova.api.openstack:FaultWrapper.factory -# DEPRECATED: NoAuthMiddleware will be removed in a subsequent release, -# whereupon this filter will cease to function. -[filter:noauth2] -paste.filter_factory = nova.api.openstack.auth:NoAuthMiddleware.factory - [filter:osprofiler] paste.filter_factory = nova.profiler:WsgiMiddleware.factory diff --git a/nova/api/auth.py b/nova/api/auth.py index 31e625d394b5..5d96bc8d7e51 100644 --- a/nova/api/auth.py +++ b/nova/api/auth.py @@ -17,7 +17,6 @@ Common Auth Middleware. """ from oslo_log import log as logging -from oslo_log import versionutils from oslo_serialization import jsonutils import webob.dec import webob.exc @@ -43,16 +42,7 @@ def _load_pipeline(loader, pipeline): def pipeline_factory_v21(loader, global_conf, **local_conf): """A paste pipeline replica that keys off of auth_strategy.""" - auth_strategy = CONF.api.auth_strategy - if auth_strategy == 'noauth2': - versionutils.report_deprecated_feature( - LOG, - "'[api]auth_strategy=noauth2' is deprecated as of the 21.0.0 " - "Ussuri release and will be removed in a future release. Please " - "remove any 'noauth2' entries from api-paste.ini; only the " - "'keystone' pipeline is supported." - ) - return _load_pipeline(loader, local_conf[auth_strategy].split()) + return _load_pipeline(loader, local_conf['keystone'].split()) class InjectContext(wsgi.Middleware): diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py deleted file mode 100644 index 214386f0d44a..000000000000 --- a/nova/api/openstack/auth.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2013 IBM Corp. -# Copyright 2010 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. - -from oslo_middleware import request_id -import webob.dec -import webob.exc - -from nova.api.openstack import wsgi -from nova.api import wsgi as base_wsgi -import nova.conf -from nova import context - -CONF = nova.conf.CONF - - -class NoAuthMiddlewareBase(base_wsgi.Middleware): - """Return a fake token if one isn't specified.""" - - def base_call(self, req, project_id_in_path, always_admin=True): - if 'X-Auth-Token' not in req.headers: - user_id = req.headers.get('X-Auth-User', 'admin') - project_id = req.headers.get('X-Auth-Project-Id', 'admin') - if project_id_in_path: - os_url = '/'.join([req.url.rstrip('/'), project_id]) - else: - os_url = req.url.rstrip('/') - res = webob.Response() - # NOTE(vish): This is expecting and returning Auth(1.1), whereas - # keystone uses 2.0 auth. We should probably allow - # 2.0 auth here as well. - res.headers['X-Auth-Token'] = '%s:%s' % (user_id, project_id) - res.headers['X-Server-Management-Url'] = os_url - res.content_type = 'text/plain' - res.status = '204' - return res - - token = req.headers['X-Auth-Token'] - user_id, _sep, project_id = token.partition(':') - project_id = project_id or user_id - remote_address = getattr(req, 'remote_addr', '127.0.0.1') - is_admin = always_admin or (user_id == 'admin') - ctx = context.RequestContext( - user_id, project_id, is_admin=is_admin, - remote_address=remote_address, - request_id=req.environ.get(request_id.ENV_REQUEST_ID)) - - req.environ['nova.context'] = ctx - return self.application - - -class NoAuthMiddleware(NoAuthMiddlewareBase): - """Return a fake token if one isn't specified. - - noauth2 provides admin privs if 'admin' is provided as the user id. - - """ - @webob.dec.wsgify(RequestClass=wsgi.Request) - def __call__(self, req): - return self.base_call(req, True, always_admin=False) - - -class NoAuthMiddlewareV2_18(NoAuthMiddlewareBase): - """Return a fake token if one isn't specified. - - This provides a version of the middleware which does not add - project_id into server management urls. - - """ - - @webob.dec.wsgify(RequestClass=wsgi.Request) - def __call__(self, req): - return self.base_call(req, False, always_admin=False) diff --git a/nova/conf/api.py b/nova/conf/api.py index c462321888e1..d047772c4e4b 100644 --- a/nova/conf/api.py +++ b/nova/conf/api.py @@ -21,27 +21,6 @@ api_group = cfg.OptGroup('api', Options under this group are used to define Nova API. """) -auth_opts = [ - cfg.StrOpt("auth_strategy", - default="keystone", - choices=[ - ("keystone", "Use keystone for authentication."), - ("noauth2", "Designed for testing only, as it does no actual " - "credential checking. 'noauth2' provides administrative " - "credentials only if 'admin' is specified as the username."), - ], - deprecated_for_removal=True, - deprecated_since='21.0.0', - deprecated_reason=""" -The only non-default choice, ``noauth2``, is for internal development and -testing purposes only and should not be used in deployments. This option and -its middleware, NoAuthMiddleware[V2_18], will be removed in a future release. -""", - help=""" -Determine the strategy to use for authentication. -"""), -] - metadata_opts = [ cfg.StrOpt("config_drive_skip_versions", default=("1.0 2007-01-19 2007-03-01 2007-08-29 2007-10-10 " @@ -411,13 +390,14 @@ issues you are seeing to the Nova team so we can improve our schemas. ), ] -API_OPTS = (auth_opts + - metadata_opts + - file_opts + - osapi_opts + - os_network_opts + - enable_inst_pw_opts + - validation_opts) +API_OPTS = ( + metadata_opts + + file_opts + + osapi_opts + + os_network_opts + + enable_inst_pw_opts + + validation_opts +) def register_opts(conf): diff --git a/nova/tests/fixtures/__init__.py b/nova/tests/fixtures/__init__.py index 9a9b890a8bf1..ffacab8ea021 100644 --- a/nova/tests/fixtures/__init__.py +++ b/nova/tests/fixtures/__init__.py @@ -10,8 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -from .api_paste import ApiPasteNoProjectId # noqa: F401, H304 -from .api_paste import ApiPasteV21Fixture # noqa: F401, H304 from .cast_as_call import CastAsCallFixture # noqa: F401, H304 from .cinder import CinderFixture # noqa: F401, H304 from .conf import ConfFixture # noqa: F401, H304, F403 diff --git a/nova/tests/fixtures/api_paste.py b/nova/tests/fixtures/api_paste.py deleted file mode 100644 index 57bc897203b9..000000000000 --- a/nova/tests/fixtures/api_paste.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2015 NEC Corporation. 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. - -import os - -import fixtures - -import nova.conf -from nova.conf import paths - -CONF = nova.conf.CONF - - -class ApiPasteV21Fixture(fixtures.Fixture): - - def _replace_line(self, target_file, line): - # TODO(johnthetubaguy) should really point the tests at /v2.1 - target_file.write(line.replace( - "/v2: openstack_compute_api_v21_legacy_v2_compatible", - "/v2: openstack_compute_api_v21")) - - def setUp(self): - super(ApiPasteV21Fixture, self).setUp() - CONF.set_default('api_paste_config', - paths.state_path_def('etc/nova/api-paste.ini'), - group='wsgi') - tmp_api_paste_dir = self.useFixture(fixtures.TempDir()) - tmp_api_paste_file_name = os.path.join(tmp_api_paste_dir.path, - 'fake_api_paste.ini') - with open(CONF.wsgi.api_paste_config, 'r') as orig_api_paste: - with open(tmp_api_paste_file_name, 'w') as tmp_file: - for line in orig_api_paste: - self._replace_line(tmp_file, line) - CONF.set_override('api_paste_config', tmp_api_paste_file_name, - group='wsgi') - - -class ApiPasteNoProjectId(ApiPasteV21Fixture): - - def _replace_line(self, target_file, line): - line = line.replace( - "paste.filter_factory = nova.api.openstack.auth:" - "NoAuthMiddleware.factory", - "paste.filter_factory = nova.api.openstack.auth:" - "NoAuthMiddlewareV2_18.factory") - target_file.write(line) diff --git a/nova/tests/functional/api_sample_tests/api_sample_base.py b/nova/tests/functional/api_sample_tests/api_sample_base.py index c801ae6d1855..7477e2b98301 100644 --- a/nova/tests/functional/api_sample_tests/api_sample_base.py +++ b/nova/tests/functional/api_sample_tests/api_sample_base.py @@ -18,7 +18,6 @@ import testscenarios import nova.conf from nova.tests import fixtures -from nova.tests.fixtures import api_paste as api_paste_fixture from nova.tests.functional import api_samples_test_base CONF = nova.conf.CONF @@ -71,17 +70,14 @@ class ApiSampleTestBaseV21(testscenarios.WithScenarios, scenarios = [ # test v2 with the v2.1 compatibility stack - ('v2', { - 'api_major_version': 'v2'}), + ('v2', {'api_major_version': 'v2'}), # test v2.1 base microversion - ('v2_1', { - 'api_major_version': 'v2.1'}), + ('v2_1', {'api_major_version': 'v2.1'}), # test v2.18 code without project id - ('v2_1_noproject_id', { - 'api_major_version': 'v2.1', - 'USE_PROJECT_ID': False, - '_additional_fixtures': [ - api_paste_fixture.ApiPasteNoProjectId]}) + ( + 'v2_1_noproject_id', + {'api_major_version': 'v2.1', 'USE_PROJECT_ID': False}, + ), ] def setUp(self): diff --git a/nova/tests/functional/api_sample_tests/test_versions.py b/nova/tests/functional/api_sample_tests/test_versions.py index e67eb839bc60..fbf865ba9fb8 100644 --- a/nova/tests/functional/api_sample_tests/test_versions.py +++ b/nova/tests/functional/api_sample_tests/test_versions.py @@ -12,9 +12,8 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + import ddt -import fixtures -import webob from nova.api.openstack import api_version_request as avr from nova.tests.functional.api_sample_tests import api_sample_base @@ -39,15 +38,6 @@ class VersionsSampleJsonTest(api_sample_base.ApiSampleTestBaseV21): scenarios = [] max_api_version = {'max_api_version': avr.max_api_version().get_string()} - def setUp(self): - super(VersionsSampleJsonTest, self).setUp() - # Version documents are supposed to be available without auth, so make - # the auth middleware "fail" authentication. - self.useFixture(fixtures.MockPatch( - # [api]auth_strategy is set to noauth2 by the ConfFixture - 'nova.api.openstack.auth.NoAuthMiddlewareBase.base_call', - return_value=webob.Response(status=401))) - def _get(self, url): return self._do_get( url, diff --git a/nova/tests/unit/api/openstack/compute/test_auth.py b/nova/tests/unit/api/openstack/compute/test_auth.py deleted file mode 100644 index eba453b58032..000000000000 --- a/nova/tests/unit/api/openstack/compute/test_auth.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2013 IBM Corp. -# Copyright 2010 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. - -import testscenarios - -from nova.api import openstack as openstack_api -from nova.api.openstack import auth -from nova.api.openstack import compute -from nova.api.openstack import urlmap -from nova import test -from nova.tests.unit.api.openstack import fakes - - -class TestNoAuthMiddleware(testscenarios.WithScenarios, test.NoDBTestCase): - - scenarios = [ - ('project_id', { - 'expected_url': 'http://localhost/v2.1/user1_project', - 'auth_middleware': auth.NoAuthMiddleware}), - ('no_project_id', { - 'expected_url': 'http://localhost/v2.1', - 'auth_middleware': auth.NoAuthMiddlewareV2_18}), - ] - - def setUp(self): - super(TestNoAuthMiddleware, self).setUp() - fakes.stub_out_networking(self) - api_v21 = openstack_api.FaultWrapper( - self.auth_middleware( - compute.APIRouterV21() - ) - ) - self.wsgi_app = urlmap.URLMap() - self.wsgi_app['/v2.1'] = api_v21 - self.req_url = '/v2.1' - - def test_authorize_user(self): - req = fakes.HTTPRequest.blank(self.req_url, base_url='') - req.headers['X-Auth-User'] = 'user1' - req.headers['X-Auth-Key'] = 'user1_key' - req.headers['X-Auth-Project-Id'] = 'user1_project' - result = req.get_response(self.wsgi_app) - self.assertEqual(result.status, '204 No Content') - self.assertEqual(result.headers['X-Server-Management-Url'], - self.expected_url) - - def test_authorize_user_trailing_slash(self): - # make sure it works with trailing slash on the request - self.req_url = self.req_url + '/' - req = fakes.HTTPRequest.blank(self.req_url, base_url='') - req.headers['X-Auth-User'] = 'user1' - req.headers['X-Auth-Key'] = 'user1_key' - req.headers['X-Auth-Project-Id'] = 'user1_project' - result = req.get_response(self.wsgi_app) - self.assertEqual(result.status, '204 No Content') - self.assertEqual(result.headers['X-Server-Management-Url'], - self.expected_url) - - def test_auth_token_no_empty_headers(self): - req = fakes.HTTPRequest.blank(self.req_url, base_url='') - req.headers['X-Auth-User'] = 'user1' - req.headers['X-Auth-Key'] = 'user1_key' - req.headers['X-Auth-Project-Id'] = 'user1_project' - result = req.get_response(self.wsgi_app) - self.assertEqual(result.status, '204 No Content') - self.assertNotIn('X-CDN-Management-Url', result.headers) - self.assertNotIn('X-Storage-Url', result.headers) diff --git a/nova/tests/unit/api/openstack/test_auth.py b/nova/tests/unit/api/openstack/test_auth.py deleted file mode 100644 index 06a38c5c452a..000000000000 --- a/nova/tests/unit/api/openstack/test_auth.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) 2018 OpenStack Foundation -# -# 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. - -from oslo_middleware import request_id -from oslo_serialization import jsonutils -import webob -import webob.exc - -import nova.api.openstack.auth -import nova.conf -from nova import test - -CONF = nova.conf.CONF - - -class NoAuthMiddleware(test.NoDBTestCase): - - def setUp(self): - super(NoAuthMiddleware, self).setUp() - - @webob.dec.wsgify() - def fake_app(req): - self.context = req.environ['nova.context'] - return webob.Response() - - self.context = None - self.middleware = nova.api.openstack.auth.NoAuthMiddleware(fake_app) - self.request = webob.Request.blank('/') - self.request.headers['X_TENANT_ID'] = 'testtenantid' - self.request.headers['X_AUTH_TOKEN'] = 'testauthtoken' - self.request.headers['X_SERVICE_CATALOG'] = jsonutils.dumps({}) - - def test_request_id_extracted_from_env(self): - req_id = 'dummy-request-id' - self.request.headers['X_PROJECT_ID'] = 'testtenantid' - self.request.headers['X_USER_ID'] = 'testuserid' - self.request.environ[request_id.ENV_REQUEST_ID] = req_id - self.request.get_response(self.middleware) - self.assertEqual(req_id, self.context.request_id) diff --git a/nova/tests/unit/api/test_auth.py b/nova/tests/unit/api/test_auth.py index 01909a90c8e9..3e8aa403e785 100644 --- a/nova/tests/unit/api/test_auth.py +++ b/nova/tests/unit/api/test_auth.py @@ -133,28 +133,15 @@ class TestPipeLineFactory(test.NoDBTestCase): def get_app(self, name): return TestPipeLineFactory.FakeApp(name) - def _test_pipeline(self, pipeline, app): - for p in pipeline.split()[:-1]: - self.assertEqual(app.name, p) - self.assertIsInstance(app, TestPipeLineFactory.FakeFilter) - app = app.obj - self.assertEqual(app.name, pipeline.split()[-1]) - self.assertIsInstance(app, TestPipeLineFactory.FakeApp) - @mock.patch('oslo_log.versionutils.report_deprecated_feature', new=mock.NonCallableMock()) def test_pipeline_factory_v21(self): fake_pipeline = 'test1 test2 test3' - CONF.set_override('auth_strategy', 'keystone', group='api') app = nova.api.auth.pipeline_factory_v21( TestPipeLineFactory.FakeLoader(), None, keystone=fake_pipeline) - self._test_pipeline(fake_pipeline, app) - - @mock.patch('oslo_log.versionutils.report_deprecated_feature') - def test_pipeline_factory_v21_noauth2(self, mock_report_deprecated): - fake_pipeline = 'test1 test2 test3' - CONF.set_override('auth_strategy', 'noauth2', group='api') - app = nova.api.auth.pipeline_factory_v21( - TestPipeLineFactory.FakeLoader(), None, noauth2=fake_pipeline) - self._test_pipeline(fake_pipeline, app) - self.assertTrue(mock_report_deprecated.called) + for p in fake_pipeline.split()[:-1]: + self.assertEqual(app.name, p) + self.assertIsInstance(app, TestPipeLineFactory.FakeFilter) + app = app.obj + self.assertEqual(app.name, fake_pipeline.split()[-1]) + self.assertIsInstance(app, TestPipeLineFactory.FakeApp)