diff --git a/doc/source/middlewarearchitecture.rst b/doc/source/middlewarearchitecture.rst index bc1c5049..123b8417 100644 --- a/doc/source/middlewarearchitecture.rst +++ b/doc/source/middlewarearchitecture.rst @@ -174,11 +174,12 @@ when ``auth_plugin`` is set to ``password``. user_domain_name = Default username = nova password = ServicePassword + interface = public auth_url = http://127.0.0.1:5000 # Any of the options that could be set in api-paste.ini can be set here. If using an ``auth_plugin``, connection to the Identity service will be -established on the ``admin`` interface as registered in the service catalog. +established on the ``interface`` as registered in the service catalog. In the case where you are using an ``auth_plugin`` and have multiple regions, also specify the ``region_name`` option to fetch the correct endpoint. diff --git a/keystonemiddleware/auth_token/__init__.py b/keystonemiddleware/auth_token/__init__.py index 72ba2239..6041e9ea 100644 --- a/keystonemiddleware/auth_token/__init__.py +++ b/keystonemiddleware/auth_token/__init__.py @@ -251,7 +251,6 @@ _LOG = logging.getLogger(__name__) _CACHE_INVALID_INDICATOR = 'invalid' oslo_cache.configure(cfg.CONF) - AUTH_TOKEN_OPTS = [ (_base.AUTHTOKEN_GROUP, _opts._OPTS + _auth.OPTS + loading.get_auth_common_conf_options()) @@ -570,6 +569,7 @@ class AuthProtocol(BaseAuthProtocol): self._include_service_catalog = self._conf.get( 'include_service_catalog') self._hash_algorithms = self._conf.get('hash_algorithms') + self._interface = self._conf.get('interface') self._auth = self._create_auth_plugin() self._session = self._create_session() @@ -907,7 +907,7 @@ class AuthProtocol(BaseAuthProtocol): self._session, auth=self._auth, service_type='identity', - interface='admin', + interface=self._interface, region_name=self._conf.get('region_name'), connect_retries=self._conf.get('http_request_max_retries')) @@ -918,7 +918,8 @@ class AuthProtocol(BaseAuthProtocol): self.log, adap, include_service_catalog=self._include_service_catalog, - requested_auth_version=auth_version) + requested_auth_version=auth_version, + requested_auth_interface=self._interface) def _create_oslo_cache(self): # having this as a function makes test mocking easier diff --git a/keystonemiddleware/auth_token/_identity.py b/keystonemiddleware/auth_token/_identity.py index 36639a6b..aeeb8d94 100644 --- a/keystonemiddleware/auth_token/_identity.py +++ b/keystonemiddleware/auth_token/_identity.py @@ -41,8 +41,10 @@ class _RequestStrategy(object): AUTH_VERSION = None - def __init__(self, adap, include_service_catalog=None): + def __init__(self, adap, include_service_catalog=None, + requested_auth_interface=None): self._include_service_catalog = include_service_catalog + self._requested_auth_interface = requested_auth_interface def verify_token(self, user_token, allow_expired=False): pass @@ -93,7 +95,10 @@ class _V3RequestStrategy(_RequestStrategy): def __init__(self, adap, **kwargs): super(_V3RequestStrategy, self).__init__(adap, **kwargs) - self._client = v3_client.Client(session=adap) + client_args = {'session': adap} + if self._requested_auth_interface: + client_args['interface'] = self._requested_auth_interface + self._client = v3_client.Client(**client_args) def verify_token(self, token, allow_expired=False): auth_ref = self._client.tokens.validate( @@ -128,11 +133,12 @@ class IdentityServer(object): """ def __init__(self, log, adap, include_service_catalog=None, - requested_auth_version=None): + requested_auth_version=None, requested_auth_interface=None): self._LOG = log self._adapter = adap self._include_service_catalog = include_service_catalog self._requested_auth_version = requested_auth_version + self._requested_auth_interface = requested_auth_interface # Built on-demand with self._request_strategy. self._request_strategy_obj = None @@ -163,7 +169,8 @@ class IdentityServer(object): self._request_strategy_obj = strategy_class( self._adapter, - include_service_catalog=self._include_service_catalog) + include_service_catalog=self._include_service_catalog, + requested_auth_interface=self._requested_auth_interface) return self._request_strategy_obj diff --git a/keystonemiddleware/auth_token/_opts.py b/keystonemiddleware/auth_token/_opts.py index 941d0adb..6231b6db 100644 --- a/keystonemiddleware/auth_token/_opts.py +++ b/keystonemiddleware/auth_token/_opts.py @@ -66,7 +66,11 @@ _OPTS = [ ' favor of www_authenticate_uri and will be removed in the S' ' release.'), cfg.StrOpt('auth_version', - help='API version of the admin Identity API endpoint.'), + help='API version of the Identity API endpoint.'), + cfg.StrOpt('interface', + default='admin', + help='Interface to use for the Identity API endpoint. Valid' + ' values are "public", "internal" or "admin"(default).'), cfg.BoolOpt('delay_auth_decision', default=False, help='Do not handle authorization requests within the' diff --git a/keystonemiddleware/tests/unit/test_opts.py b/keystonemiddleware/tests/unit/test_opts.py index 3b4e510e..143264c9 100644 --- a/keystonemiddleware/tests/unit/test_opts.py +++ b/keystonemiddleware/tests/unit/test_opts.py @@ -33,6 +33,7 @@ class OptsTestCase(utils.TestCase): expected_opt_names = [ 'auth_admin_prefix', 'auth_host', + 'interface', 'auth_port', 'auth_protocol', 'www_authenticate_uri', @@ -86,6 +87,7 @@ class OptsTestCase(utils.TestCase): # This is the sample config generator list WITHOUT deprecations expected_opt_names = [ 'www_authenticate_uri', + 'interface', 'auth_uri', 'auth_version', 'delay_auth_decision', diff --git a/releasenotes/notes/interface-option-ed551d2a3162668d.yaml b/releasenotes/notes/interface-option-ed551d2a3162668d.yaml new file mode 100644 index 00000000..4771e869 --- /dev/null +++ b/releasenotes/notes/interface-option-ed551d2a3162668d.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + [`bug 1830002 `_] + In order to allow an installation to work without deploying an admin + Identity endpoint, a new option `interface` has been added, allowing + select the Identity endpoint that is being used when verifying auth + tokens. It defaults to `admin` in order to replicate the old behaviour, + but may be set to `public` or `internal` as needed.