Keystone adheres to public_endpoint opt only

With the complete removal of the v2.0 API, keystone no longer
differentiates between admin and public endpoints. This change
deprecates the "admin_endpoint" configuration option and converts
keystone over to only using the public endpoint. The "admin" endpoint
was only used for unit testing purposes.

This change does not clean up all code related, it is aimed to make
the most minimal set of changes eliminating the use of the
"admin_endpoint" configuration option.

Partial-Bug: #1776504
Change-Id: I08f6f8ae078d65203bd95c43c80367dd3489be48
This commit is contained in:
Morgan Fainberg 2018-06-11 17:25:45 -07:00
parent 925cded08b
commit ecf721a3c1
8 changed files with 44 additions and 82 deletions

View File

@ -44,7 +44,7 @@ WHITELISTED_PROPERTIES = [
'tenant_id', 'project_id', 'user_id',
'public_bind_host', 'admin_bind_host',
'compute_host', 'admin_port', 'public_port',
'public_endpoint', 'admin_endpoint', ]
'public_endpoint', ]
# NOTE(stevermar): This UUID must stay the same, forever, across

View File

@ -305,14 +305,8 @@ class Application(BaseApplication):
raise exception.ValidationError(message=msg)
@classmethod
def base_url(cls, context, endpoint_type):
# NOTE(morgan): endpoint type must be "admin" or "public" to lookup
# the relevant value from the config options. Make the error clearer
# if we somehow got here with a different endpoint type.
if endpoint_type not in ('admin', 'public'):
raise ValueError('PROGRAMMING ERROR: Endpoint type must be '
'"admin" or "public".')
url = CONF['%s_endpoint' % endpoint_type]
def base_url(cls, context, endpoint_type=None):
url = CONF['public_endpoint']
if url:
substitutions = dict(
@ -764,7 +758,7 @@ def render_exception(error, context=None, request=None, user_locale=None):
local_context = {'environment': request.environ}
elif context and 'environment' in context:
local_context = {'environment': context['environment']}
url = Application.base_url(local_context, 'public')
url = Application.base_url(local_context)
headers.append(('WWW-Authenticate', 'Keystone uri="%s"' % url))
return render_response(status=(error.code, error.title),

View File

@ -57,6 +57,12 @@ infer (`/prefix/v3`), or if the endpoint should be found on a different host.
admin_endpoint = cfg.URIOpt(
'admin_endpoint',
deprecated_since=versionutils.deprecated.ROCKY,
deprecated_for_removal=True,
deprecated_reason=utils.fmt("""
With the removal of the 2.0 API keystone does not distinguish between admin
and public endpoints.
"""),
help=utils.fmt("""
The base admin endpoint URL for Keystone that is advertised to clients (NOTE:
this does NOT affect how Keystone listens for connections). Defaults to the

View File

@ -20,11 +20,11 @@ from keystone.server.flask import core as flask_core
# import core and call it directly, eventually keystone_flask will not
# export all the symbols from keystone.flask.core only specific ones that
# are meant for public consumption
def initialize_admin_application():
return keystone_flask.initialize_application(
name='admin', config_files=flask_core._get_config_files())
def initialize_public_application():
return keystone_flask.initialize_application(
name='public', config_files=flask_core._get_config_files())
# Keystone does not differentiate between "admin" and public with the removal
# of V2.0
initialize_admin_application = initialize_public_application

View File

@ -66,9 +66,6 @@ class RestfulTestCase(unit.TestCase):
self.public_app = webtest.TestApp(
self.loadapp(name='public'))
self.addCleanup(delattr, self, 'public_app')
self.admin_app = webtest.TestApp(
self.loadapp(name='admin'))
self.addCleanup(delattr, self, 'admin_app')
def auth_plugin_config_override(self, methods=None, **method_classes):
self.useFixture(
@ -213,7 +210,7 @@ class RestfulTestCase(unit.TestCase):
return self._request(app=self.public_app, **kwargs)
def admin_request(self, **kwargs):
return self._request(app=self.admin_app, **kwargs)
return self._request(app=self.public_app, **kwargs)
def _get_token_id(self, r):
"""Helper method to return a token ID from a response.

View File

@ -2339,8 +2339,8 @@ class TokenAPITests(object):
self.config_fixture.config(group='token', bind=[])
auth_data = self.build_authentication_request()
remote_user = self.default_domain_user['name']
self.admin_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
self.public_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
r = self.v3_create_token(auth_data)
token = self.assertValidUnscopedTokenResponse(r)
self.assertNotIn('bind', token)
@ -2350,8 +2350,8 @@ class TokenAPITests(object):
auth_data = self.build_authentication_request(
project_id=self.project['id'])
remote_user = self.default_domain_user['name']
self.admin_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
self.public_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
token = self.get_requested_token(auth_data)
headers = {'X-Subject-Token': token}
@ -2365,8 +2365,8 @@ class TokenAPITests(object):
auth_data = self.build_authentication_request()
remote_user = self.default_domain_user['name']
self.admin_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
self.public_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
r = self.v3_create_token(auth_data)
# the unscoped token should have bind information in it
@ -2587,8 +2587,8 @@ class TestFernetTokenAPIs(test_v3.RestfulTestCase, TokenAPITests,
auth_data = self.build_authentication_request(
project_id=self.project['id'])
remote_user = self.default_domain_user['name']
self.admin_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
self.public_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
# Bind not current supported by Fernet, see bug 1433311.
self.v3_create_token(auth_data,
expected_status=http_client.NOT_IMPLEMENTED)
@ -2598,8 +2598,8 @@ class TestFernetTokenAPIs(test_v3.RestfulTestCase, TokenAPITests,
auth_data = self.build_authentication_request()
remote_user = self.default_domain_user['name']
self.admin_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
self.public_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
# Bind not current supported by Fernet, see bug 1433311.
self.v3_create_token(auth_data,
expected_status=http_client.NOT_IMPLEMENTED)
@ -3645,9 +3645,9 @@ class AuthExternalDomainBehavior(object):
kerberos=self.kerberos)
remote_user = self.user['name']
remote_domain = self.domain['name']
self.admin_app.extra_environ.update({'REMOTE_USER': remote_user,
'REMOTE_DOMAIN': remote_domain,
'AUTH_TYPE': 'Negotiate'})
self.public_app.extra_environ.update({'REMOTE_USER': remote_user,
'REMOTE_DOMAIN': remote_domain,
'AUTH_TYPE': 'Negotiate'})
r = self.v3_create_token(auth_data)
token = self.assertValidProjectScopedTokenResponse(r)
self.assertEqual(self.user['name'], token['bind']['kerberos'])
@ -3657,9 +3657,9 @@ class AuthExternalDomainBehavior(object):
auth_data = self.build_authentication_request(kerberos=self.kerberos)
remote_user = self.user['name']
remote_domain = self.domain['name']
self.admin_app.extra_environ.update({'REMOTE_USER': remote_user,
'REMOTE_DOMAIN': remote_domain,
'AUTH_TYPE': 'Negotiate'})
self.public_app.extra_environ.update({'REMOTE_USER': remote_user,
'REMOTE_DOMAIN': remote_domain,
'AUTH_TYPE': 'Negotiate'})
r = self.v3_create_token(auth_data)
token = self.assertValidUnscopedTokenResponse(r)
self.assertEqual(self.user['name'], token['bind']['kerberos'])
@ -3703,8 +3703,8 @@ class TestAuthExternalDefaultDomain(object):
project_id=self.default_domain_project['id'],
kerberos=self.kerberos)
remote_user = self.default_domain_user['name']
self.admin_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
self.public_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
r = self.v3_create_token(auth_data)
token = self.assertValidProjectScopedTokenResponse(r)
self.assertEqual(self.default_domain_user['name'],
@ -3714,8 +3714,8 @@ class TestAuthExternalDefaultDomain(object):
self.config_fixture.config(group='token', bind=['kerberos'])
auth_data = self.build_authentication_request(kerberos=self.kerberos)
remote_user = self.default_domain_user['name']
self.admin_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
self.public_app.extra_environ.update({'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'})
r = self.v3_create_token(auth_data)
token = self.assertValidUnscopedTokenResponse(r)
self.assertEqual(self.default_domain_user['name'],

View File

@ -25,7 +25,6 @@ import webob
from keystone.common import json_home
from keystone.tests import unit
from keystone.tests.unit import utils
from keystone.version import controllers
@ -685,14 +684,10 @@ class VersionTestCase(unit.TestCase):
super(VersionTestCase, self).setUp()
self.load_backends()
self.public_app = self.loadapp('public')
self.admin_app = self.loadapp('admin')
self.admin_port = random.randint(10000, 30000)
self.public_port = random.randint(40000, 60000)
self.config_fixture.config(
public_endpoint='http://localhost:%d' % self.public_port,
admin_endpoint='http://localhost:%d' % self.admin_port)
public_endpoint='http://localhost:%d' % self.public_port)
def config_overrides(self):
super(VersionTestCase, self).config_overrides()
@ -714,22 +709,10 @@ class VersionTestCase(unit.TestCase):
version, 'http://localhost:%s/v3/' % self.public_port)
self.assertThat(data, _VersionsEqual(expected))
def test_admin_versions(self):
client = TestClient(self.admin_app)
resp = client.get('/')
self.assertEqual(300, resp.status_int)
data = jsonutils.loads(resp.body)
expected = VERSIONS_RESPONSE
for version in expected['versions']['values']:
if version['id'].startswith('v3'):
self._paste_in_port(
version, 'http://localhost:%s/v3/' % self.admin_port)
self.assertThat(data, _VersionsEqual(expected))
def test_use_site_url_if_endpoint_unset(self):
self.config_fixture.config(public_endpoint=None, admin_endpoint=None)
self.config_fixture.config(public_endpoint=None)
for app in (self.public_app, self.admin_app):
for app in (self.public_app,):
client = TestClient(app)
resp = client.get('/')
self.assertEqual(300, resp.status_int)
@ -752,20 +735,9 @@ class VersionTestCase(unit.TestCase):
'http://localhost:%s/v3/' % self.public_port)
self.assertEqual(expected, data)
@utils.wip('waiting on bug #1381961')
def test_admin_version_v3(self):
client = TestClient(self.admin_app)
resp = client.get('/v3/')
self.assertEqual(http_client.OK, resp.status_int)
data = jsonutils.loads(resp.body)
expected = v3_VERSION_RESPONSE
self._paste_in_port(expected['version'],
'http://localhost:%s/v3/' % self.admin_port)
self.assertEqual(expected, data)
def test_use_site_url_if_endpoint_unset_v3(self):
self.config_fixture.config(public_endpoint=None, admin_endpoint=None)
for app in (self.public_app, self.admin_app):
self.config_fixture.config(public_endpoint=None)
for app in (self.public_app,):
client = TestClient(app)
resp = client.get('/v3/')
self.assertEqual(http_client.OK, resp.status_int)
@ -904,12 +876,10 @@ class VersionSingleAppTestCase(unit.TestCase):
super(VersionSingleAppTestCase, self).setUp()
self.load_backends()
self.admin_port = random.randint(10000, 30000)
self.public_port = random.randint(40000, 60000)
self.config_fixture.config(
public_endpoint='http://localhost:%d' % self.public_port,
admin_endpoint='http://localhost:%d' % self.admin_port)
public_endpoint='http://localhost:%d' % self.public_port)
def config_overrides(self):
super(VersionSingleAppTestCase, self).config_overrides()
@ -920,11 +890,6 @@ class VersionSingleAppTestCase(unit.TestCase):
link['href'] = port
def _test_version(self, app_name):
def app_port():
if app_name == 'admin':
return self.admin_port
else:
return self.public_port
app = self.loadapp(app_name)
client = TestClient(app)
resp = client.get('/')
@ -934,7 +899,7 @@ class VersionSingleAppTestCase(unit.TestCase):
for version in expected['versions']['values']:
if version['id'].startswith('v3'):
self._paste_in_port(
version, 'http://localhost:%s/v3/' % app_port())
version, 'http://localhost:%s/v3/' % self.public_port)
self.assertThat(data, _VersionsEqual(expected))
def test_public(self):

View File

@ -230,7 +230,7 @@ class ApplicationTest(BaseWSGITest):
def test_base_url(self):
class FakeApp(wsgi.Application):
def index(self, request):
return self.base_url(request.context_dict, 'public')
return self.base_url(request.context_dict)
req = self._make_request(url='/')
# NOTE(gyee): according to wsgiref, if HTTP_HOST is present in the
# request environment, it will be used to construct the base url.