Kerberos as method name

To date kerberos has been supported by the "external" method
name.  However, the Client plugin architecture needs to refer to the
method name, and we do not want to expose to the client the
difference between kerberos as performed by an external module or
an eventual kerberos-in-eventlet style implementation.

If the "external" plugin is missing, the old code would throw an
exception attempting to process "REMOTE_USER" behavior.  Now, if only
'kerberos' is specified, this is checked and skipped.

Blueprint: kerberos-authentication
SecurityImpact:  Minimal, as Kerberos is already used via external,
                 this  just changes the main way it is named.

Change-Id: If698fc1d0751cded556825b081539da4dd51275e
This commit is contained in:
Adam Young 2014-05-27 21:51:12 -04:00 committed by ayoung
parent b5576ad69b
commit 37d133aa2e
4 changed files with 53 additions and 11 deletions

View File

@ -453,10 +453,19 @@ class Auth(controller.V3Controller):
def authenticate(self, context, auth_info, auth_context):
"""Authenticate user."""
# user has been authenticated externally
# The 'external' method allows any 'REMOTE_USER' based authentication
if 'REMOTE_USER' in context['environment']:
external = get_auth_method('external')
external.authenticate(context, auth_info, auth_context)
try:
external = get_auth_method('external')
external.authenticate(context, auth_info, auth_context)
except exception.AuthMethodNotSupported:
# This will happen there is no 'external' plugin registered
# and the container is performing authentication.
# The 'kerberos' and 'saml' methods will be used this way.
# In those cases, it is correct to not register an
# 'external' plugin; if there is both an 'external' and a
# 'kerberos' plugin, it would run the check on identity twice.
pass
# need to aggregate the results in case two or more methods
# are specified

View File

@ -96,6 +96,18 @@ class Domain(Base):
return user_ref
@dependency.requires('assignment_api', 'identity_api')
class KerberosDomain(Domain):
"""Allows `kerberos` as a method."""
method = 'kerberos'
def _authenticate(self, remote_user, context):
auth_type = context['environment'].get('AUTH_TYPE')
if auth_type != 'Negotiate':
raise exception.Unauthorized(_("auth_type is not Negotiate"))
return super(KerberosDomain, self)._authenticate(remote_user, context)
class ExternalDefault(DefaultDomain):
"""Deprecated. Please use keystone.auth.external.DefaultDomain instead."""

View File

@ -1115,7 +1115,7 @@ class RestfulTestCase(tests.SQLDriverOverrides, rest.RestfulTestCase):
def build_authentication_request(self, token=None, user_id=None,
username=None, user_domain_id=None,
user_domain_name=None, password=None,
**kwargs):
kerberos=False, **kwargs):
"""Build auth dictionary.
It will create an auth dictionary based on all the arguments
@ -1123,6 +1123,9 @@ class RestfulTestCase(tests.SQLDriverOverrides, rest.RestfulTestCase):
"""
auth_data = {}
auth_data['identity'] = {'methods': []}
if kerberos:
auth_data['identity']['methods'].append('kerberos')
auth_data['identity']['kerberos'] = {}
if token:
auth_data['identity']['methods'].append('token')
auth_data['identity']['token'] = self.build_token_auth(token)
@ -1135,12 +1138,15 @@ class RestfulTestCase(tests.SQLDriverOverrides, rest.RestfulTestCase):
return {'auth': auth_data}
def build_external_auth_request(self, remote_user,
remote_domain=None, auth_data=None):
context = {'environment': {'REMOTE_USER': remote_user}}
remote_domain=None, auth_data=None,
kerberos=False):
context = {'environment': {'REMOTE_USER': remote_user,
'AUTH_TYPE': 'Negotiate'}}
if remote_domain:
context['environment']['REMOTE_DOMAIN'] = remote_domain
if not auth_data:
auth_data = self.build_authentication_request()['auth']
auth_data = self.build_authentication_request(
kerberos=kerberos)['auth']
no_context = None
auth_info = auth.controllers.AuthInfo.create(no_context, auth_data)
auth_context = {'extras': {}, 'method_names': []}

View File

@ -1522,6 +1522,7 @@ class TestAuthExternalDomain(test_v3.RestfulTestCase):
def config_overrides(self):
super(TestAuthExternalDomain, self).config_overrides()
self.kerberos = False
self.config_fixture.config(
group='auth',
methods=['keystone.auth.plugins.external.Domain',
@ -1533,7 +1534,7 @@ class TestAuthExternalDomain(test_v3.RestfulTestCase):
remote_user = self.user['name']
remote_domain = self.domain['name']
context, auth_info, auth_context = self.build_external_auth_request(
remote_user, remote_domain=remote_domain)
remote_user, remote_domain=remote_domain, kerberos=self.kerberos)
api.authenticate(context, auth_info, auth_context)
self.assertEqual(auth_context['user_id'], self.user['id'])
@ -1544,7 +1545,7 @@ class TestAuthExternalDomain(test_v3.RestfulTestCase):
self.identity_api.update_user(self.user['id'], user)
remote_user = user['name']
context, auth_info, auth_context = self.build_external_auth_request(
remote_user, remote_domain=remote_domain)
remote_user, remote_domain=remote_domain, kerberos=self.kerberos)
api.authenticate(context, auth_info, auth_context)
self.assertEqual(auth_context['user_id'], self.user['id'])
@ -1552,7 +1553,8 @@ class TestAuthExternalDomain(test_v3.RestfulTestCase):
def test_project_id_scoped_with_remote_user(self):
CONF.token.bind = ['kerberos']
auth_data = self.build_authentication_request(
project_id=self.project['id'])
project_id=self.project['id'],
kerberos=self.kerberos)
remote_user = self.user['name']
remote_domain = self.domain['name']
self.admin_app.extra_environ.update({'REMOTE_USER': remote_user,
@ -1564,7 +1566,7 @@ class TestAuthExternalDomain(test_v3.RestfulTestCase):
def test_unscoped_bind_with_remote_user(self):
CONF.token.bind = ['kerberos']
auth_data = self.build_authentication_request()
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,
@ -1575,6 +1577,19 @@ class TestAuthExternalDomain(test_v3.RestfulTestCase):
self.assertEqual(token['bind']['kerberos'], self.user['name'])
class TestAuthKerberos(TestAuthExternalDomain):
def config_overrides(self):
super(TestAuthKerberos, self).config_overrides()
self.kerberos = True
self.config_fixture.config(
group='auth',
methods=['keystone.auth.plugins.external.KerberosDomain',
'keystone.auth.plugins.password.Password',
'keystone.auth.plugins.token.Token'])
class TestAuthJSON(test_v3.RestfulTestCase):
content_type = 'json'