Support service user and project in non-default domain

The domain for the service user and project couldn't be configured,
so the auth_token middleware always used the v2 API and the default
domain. With this change, the deployer can configure the domain for
the service user and project and the auth_token middleware will then
use the v3 API to get the service token.

DocImpact
Closes-Bug: #1372142

Change-Id: I4f65adb523a591816a6cd807070d92ce6e414a1b
This commit is contained in:
Brant Knudson 2014-09-21 11:46:46 -05:00
parent 1f8b4fe443
commit bb00caf15b
4 changed files with 90 additions and 6 deletions

View File

@ -165,6 +165,12 @@ a WSGI component. Example for the auth_token middleware::
# Keystone account username (string value)
#admin_user=<None>
# Keystone service account user domain ID. (string value)
#admin_user_domain_id=<None>
# Keystone service account user domain name. (string value)
#admin_user_domain_name=<None>
# Keystone account password (string value)
admin_password=SuperSekretPassword
@ -172,6 +178,12 @@ a WSGI component. Example for the auth_token middleware::
# (string value)
#admin_tenant_name=admin
# Keystone service account project domain ID. (string value)
#admin_project_domain_id=<None>
# Keystone service account project domain name. (string value)
#admin_project_domain_name=<None>
# Env key for the swift cache (string value)
#cache=<None>
@ -292,10 +304,15 @@ Configuration Options
* ``admin_token``: either this or the following three options are required. If
set, this is a single shared secret with the keystone configuration used to
validate tokens.
* ``admin_user``, ``admin_password``, ``admin_tenant_name``: if ``admin_token``
is not set, or invalid, then admin_user, admin_password, and
admin_tenant_name are defined as a service account which is expected to have
been previously configured in Keystone to validate user tokens.
* ``admin_user``, ``admin_user_domain_name``, ``admin_user_domain_id``,
``admin_password``, ``admin_tenant_name``, ``admin_project_domain_id``,
``admin_project_domain_name``: if ``admin_token``
is not set, or invalid, then ``admin_user``, ``admin_password``, and
``admin_tenant_name`` are defined as a service account which is expected to
have been previously configured in Keystone to validate user tokens. If the
service user isn't in the default domain, set ``admin_user_domain_name`` or
``admin_user_domain_id``. If the service project isn't in the default domain,
set ``admin_project_domain_id`` or ``admin_project_domain_name``.
* ``cache``: (optional) Env key for the swift cache

View File

@ -161,6 +161,7 @@ import time
from keystoneclient import access
from keystoneclient.auth.identity import base as base_identity
from keystoneclient.auth.identity import v2
from keystoneclient.auth.identity import v3
from keystoneclient.auth import token_endpoint
from keystoneclient.common import cms
from keystoneclient import exceptions
@ -257,6 +258,10 @@ _OPTS = [
' instead.'),
cfg.StrOpt('admin_user',
help='Keystone account username'),
cfg.StrOpt('admin_user_domain_id',
help='Keystone service account user domain ID.'),
cfg.StrOpt('admin_user_domain_name',
help='Keystone service account user domain name.'),
cfg.StrOpt('admin_password',
secret=True,
help='Keystone account password'),
@ -264,6 +269,10 @@ _OPTS = [
default='admin',
help='Keystone service account tenant name to validate'
' user tokens'),
cfg.StrOpt('admin_project_domain_id',
help='Keystone service account project domain ID.'),
cfg.StrOpt('admin_project_domain_name',
help='Keystone service account project domain name.'),
cfg.StrOpt('cache',
default=None,
help='Env key for the swift cache'),
@ -1121,21 +1130,37 @@ class AuthProtocol(object):
# of this can be changed when we get keystoneclient 0.10. For now this
# hardcoded path is EXACTLY the same as the original auth_token did.
auth_url = '%s/v2.0' % self._identity_uri
auth_plugin = None
admin_token = self._conf_get('admin_token')
admin_user_domain_id = self._conf_get('admin_user_domain_id')
admin_user_domain_name = self._conf_get('admin_user_domain_name')
if admin_token:
self._LOG.warning(
"The admin_token option in the auth_token middleware is "
"deprecated and should not be used. The admin_user and "
"admin_password options should be used instead. The "
"admin_token option may be removed in a future release.")
sess.auth = token_endpoint.Token(auth_url, admin_token)
auth_plugin = token_endpoint.Token(auth_url, admin_token)
elif admin_user_domain_id or admin_user_domain_name:
auth_url = '%s/v3' % self._identity_uri
project_domain_name = self._conf_get('admin_project_domain_name')
auth_plugin = v3.Password(
auth_url,
username=self._conf_get('admin_user'),
user_domain_id=admin_user_domain_id,
user_domain_name=admin_user_domain_name,
password=self._conf_get('admin_password'),
project_name=self._conf_get('admin_tenant_name'),
project_domain_id=self._conf_get('admin_project_domain_id'),
project_domain_name=project_domain_name)
else:
sess.auth = v2.Password(
auth_plugin = v2.Password(
auth_url,
username=self._conf_get('admin_user'),
password=self._conf_get('admin_password'),
tenant_name=self._conf_get('admin_tenant_name'))
sess.auth = auth_plugin
return sess
def _identity_server_factory(self):

View File

@ -575,6 +575,44 @@ class GeneralAuthTokenMiddlewareTest(BaseAuthTokenMiddlewareTest,
self.assertRaises(auth_token.ConfigurationError,
auth_token.AuthProtocol, self.fake_app, conf)
def test_service_auth_domain_name(self):
# When the service user and project domain name is configured, the V3
# password plugin is used.
user_domain_name = uuid.uuid4().hex
project_domain_name = uuid.uuid4().hex
conf = {
'admin_user_domain_name': user_domain_name,
'admin_project_domain_name': project_domain_name,
}
self.set_middleware(conf=conf)
auth_plugin = self.middleware._session.auth
self.assertEqual(project_domain_name, auth_plugin.project_domain_name)
auth_method = auth_plugin.auth_methods[0]
self.assertEqual(user_domain_name, auth_method.user_domain_name)
def test_service_user_domain_id(self):
# When the service user and project domain ID is configured, the V3
# password plugin is used.
user_domain_id = uuid.uuid4().hex
project_domain_id = uuid.uuid4().hex
conf = {
'admin_user_domain_id': user_domain_id,
'admin_project_domain_id': project_domain_id,
}
self.set_middleware(conf=conf)
auth_plugin = self.middleware._session.auth
self.assertEqual(project_domain_id, auth_plugin.project_domain_id)
auth_method = auth_plugin.auth_methods[0]
self.assertEqual(user_domain_id, auth_method.user_domain_id)
class CommonAuthTokenMiddlewareTest(object):
"""These tests are run once using v2 tokens and again using v3 tokens."""

View File

@ -40,8 +40,12 @@ class OptsTestCase(utils.TestCase):
'http_request_max_retries',
'admin_token',
'admin_user',
'admin_user_domain_id',
'admin_user_domain_name',
'admin_password',
'admin_tenant_name',
'admin_project_domain_id',
'admin_project_domain_name',
'cache',
'certfile',
'keyfile',