summaryrefslogtreecommitdiffstats
path: root/keystone
diff options
context:
space:
mode:
authorAlvaro Lopez Garcia <aloga@ifca.unican.es>2012-11-05 10:56:40 +0100
committerAlvaro Lopez Garcia <aloga@ifca.unican.es>2012-11-15 10:04:47 +0100
commitbe754ff2bc05a0d262469edd7ce8fac19d457231 (patch)
treecf33aa941544261f8d9206c0ea088ef6fd036777 /keystone
parent2b83d4da7aca79c48f2789930bd5790bf993a606 (diff)
Refactor TokenController.authenticate() method.
Change-Id: I29710f749c67cf83ccad12deee54fe6b71dd53b8
Diffstat (limited to 'keystone')
-rw-r--r--keystone/service.py386
1 files changed, 216 insertions, 170 deletions
diff --git a/keystone/service.py b/keystone/service.py
index f31229bf..21d9303c 100644
--- a/keystone/service.py
+++ b/keystone/service.py
@@ -414,6 +414,10 @@ class NoopController(wsgi.Application):
return {}
+class ExternalAuthNotApplicable(Exception):
+ """External authentication is not applicable"""
+
+
class TokenController(wsgi.Application):
def __init__(self):
self.catalog_api = catalog.Manager()
@@ -455,182 +459,48 @@ class TokenController(wsgi.Application):
Alternatively, this call accepts auth with only a token and tenant
that will return a token that is scoped to that tenant.
"""
- if not auth:
- raise exception.ValidationError(attribute='auth',
- target='request body')
if auth is None:
- auth = {}
- remote_auth = False
- if 'REMOTE_USER' in context and not 'token' in auth:
- # authenticated external request
- remote_auth = True
-
- if 'passwordCredentials' not in auth:
- auth['passwordCredentials'] = {}
- auth['passwordCredentials']['username'] = context.get(
- 'REMOTE_USER', None)
-
- if 'passwordCredentials' in auth:
- user_id = auth['passwordCredentials'].get('userId', None)
- username = auth['passwordCredentials'].get('username', '')
- password = auth['passwordCredentials'].get('password', '')
- tenant_name = auth.get('tenantName', None)
-
- if not user_id and not username:
- raise exception.ValidationError(
- attribute='username or userId',
- target='passwordCredentials')
-
- tenant_ref = None
- user_ref = None
- metadata_ref = {}
-
- if username:
- try:
- user_ref = self.identity_api.get_user_by_name(
- context=context, user_name=username)
- user_id = user_ref['id']
- except exception.UserNotFound:
- raise exception.Unauthorized()
-
- if not password and not remote_auth:
- raise exception.ValidationError(
- attribute='password',
- target='passwordCredentials')
-
- # more compat
- tenant_id = auth.get('tenantId', None)
- if tenant_name:
- try:
- tenant_ref = self.identity_api.get_tenant_by_name(
- context=context, tenant_name=tenant_name)
- tenant_id = tenant_ref['id']
- except exception.TenantNotFound:
- raise exception.Unauthorized()
-
- try:
- if not remote_auth:
- # local identity authentication required
- auth_info = self.identity_api.authenticate(
- context=context,
- user_id=user_id,
- password=password,
- tenant_id=tenant_id)
- (user_ref, tenant_ref, metadata_ref) = auth_info
- else:
- # remote authentication already performed
- if not user_ref:
- user_ref = self.identity_api.get_user(
- self.identity_api,
- user_id)
- if tenant_id:
- if not tenant_ref:
- tenant_ref = self.identity_api.get_tenant(
- self.identity_api,
- tenant_id)
- metadata_ref = self.identity_api.get_metadata(
- self.identity_api,
- user_id,
- tenant_id)
- auth_info = (user_ref, tenant_ref, metadata_ref)
-
- # If the user is disabled don't allow them to authenticate
- if not user_ref.get('enabled', True):
- LOG.warning('User %s is disabled' % user_id)
- raise exception.Unauthorized()
-
- # If the tenant is disabled don't allow them to authenticate
- if tenant_ref and not tenant_ref.get('enabled', True):
- LOG.warning('Tenant %s is disabled' % tenant_id)
- raise exception.Unauthorized()
- except AssertionError as e:
- raise exception.Unauthorized(str(e))
- auth_token_data = dict(zip(['user', 'tenant', 'metadata'],
- auth_info))
- expiry = self.token_api._get_default_expire_time(context=context)
-
- if tenant_ref:
- catalog_ref = self.catalog_api.get_catalog(
- context=context,
- user_id=user_ref['id'],
- tenant_id=tenant_ref['id'],
- metadata=metadata_ref)
- else:
- catalog_ref = {}
- elif 'token' in auth:
- old_token = auth['token'].get('id', None)
- tenant_name = auth.get('tenantName')
-
- try:
- old_token_ref = self.token_api.get_token(context=context,
- token_id=old_token)
- except exception.NotFound:
- LOG.warning("Token not found: " + str(old_token))
- raise exception.Unauthorized()
-
- user_ref = old_token_ref['user']
- user_id = user_ref['id']
-
- current_user_ref = self.identity_api.get_user(context=context,
- user_id=user_id)
-
- # If the user is disabled don't allow them to authenticate
- if not current_user_ref.get('enabled', True):
- LOG.warning('User %s is disabled' % user_id)
- raise exception.Unauthorized()
-
- if tenant_name:
- tenant_ref = self.identity_api.get_tenant_by_name(
- context=context,
- tenant_name=tenant_name)
- tenant_id = tenant_ref['id']
- else:
- tenant_id = auth.get('tenantId', None)
- tenants = self.identity_api.get_tenants_for_user(context, user_id)
+ raise exception.ValidationError(attribute='auth',
+ target='request body')
- if tenant_id:
- if not tenant_id in tenants:
- LOG.warning('User %s is unauthorized for tenant %s'
- % (user_id, tenant_id))
- raise exception.Unauthorized()
+ auth_token_data = None
- expiry = old_token_ref['expires']
+ if "token" in auth:
+ # Try to authenticate using a token
+ auth_token_data, auth_info = self._authenticate_token(
+ context, auth)
+ else:
+ # Try external authentication
try:
- tenant_ref = self.identity_api.get_tenant(context=context,
- tenant_id=tenant_id)
- except exception.TenantNotFound:
- tenant_ref = None
- metadata_ref = {}
- catalog_ref = {}
- except exception.MetadataNotFound:
- metadata_ref = {}
- catalog_ref = {}
-
- # If the tenant is disabled don't allow them to authenticate
- if tenant_ref and not tenant_ref.get('enabled', True):
- LOG.warning('Tenant %s is disabled' % tenant_id)
- raise exception.Unauthorized()
-
- if tenant_ref:
- metadata_ref = self.identity_api.get_metadata(
- context=context,
- user_id=user_ref['id'],
- tenant_id=tenant_ref['id'])
- catalog_ref = self.catalog_api.get_catalog(
- context=context,
- user_id=user_ref['id'],
- tenant_id=tenant_ref['id'],
- metadata=metadata_ref)
-
- auth_token_data = dict(dict(user=current_user_ref,
- tenant=tenant_ref,
- metadata=metadata_ref))
+ auth_token_data, auth_info = self._authenticate_external(
+ context, auth)
+ except ExternalAuthNotApplicable:
+ # Try local authentication
+ auth_token_data, auth_info = self._authenticate_local(
+ context, auth)
+
+ user_ref, tenant_ref, metadata_ref = auth_info
+
+ # If the user is disabled don't allow them to authenticate
+ if not user_ref.get('enabled', True):
+ LOG.warning('User %s is disabled' % user_ref["id"])
+ raise exception.Unauthorized()
+
+ # If the tenant is disabled don't allow them to authenticate
+ if tenant_ref and not tenant_ref.get('enabled', True):
+ LOG.warning('Tenant %s is disabled' % tenant_ref["id"])
+ raise exception.Unauthorized()
+
+ if tenant_ref:
+ catalog_ref = self.catalog_api.get_catalog(
+ context=context,
+ user_id=user_ref['id'],
+ tenant_id=tenant_ref['id'],
+ metadata=metadata_ref)
else:
- raise exception.ValidationError(
- attribute='passwordCredentials or token', target='auth')
+ catalog_ref = {}
- auth_token_data['expires'] = expiry
auth_token_data['id'] = 'placeholder'
roles_ref = []
@@ -646,7 +516,6 @@ class TokenController(wsgi.Application):
if config.CONF.signing.token_format == 'UUID':
token_id = uuid.uuid4().hex
elif config.CONF.signing.token_format == 'PKI':
-
token_id = cms.cms_sign_token(json.dumps(token_data),
config.CONF.signing.certfile,
config.CONF.signing.keyfile)
@@ -675,6 +544,183 @@ class TokenController(wsgi.Application):
return token_data
+ def _authenticate_token(self, context, auth):
+ """Try to authenticate using an already existing token.
+
+ Returns auth_token_data, (user_ref, tenant_ref, metadata_ref)
+ """
+ if 'token' not in auth:
+ raise exception.ValidationError(
+ attribute='token', target='auth')
+
+ if "id" not in auth['token']:
+ raise exception.ValidationError(
+ attribute="id", target="token")
+
+ old_token = auth['token']['id']
+
+ try:
+ old_token_ref = self.token_api.get_token(context=context,
+ token_id=old_token)
+ except exception.NotFound:
+ LOG.warning("Token not found: " + str(old_token))
+ raise exception.Unauthorized()
+
+ user_ref = old_token_ref['user']
+ user_id = user_ref['id']
+
+ current_user_ref = self.identity_api.get_user(context=context,
+ user_id=user_id)
+
+ tenant_id = self._get_tenant_id_from_auth(context, auth)
+
+ tenant_ref = self._get_tenant_ref(context, user_id, tenant_id)
+ metadata_ref = self._get_metadata_ref(context, user_id, tenant_id)
+
+ expiry = old_token_ref['expires']
+ auth_token_data = self._get_auth_token_data(current_user_ref,
+ tenant_ref,
+ metadata_ref,
+ expiry)
+
+ return auth_token_data, (current_user_ref, tenant_ref, metadata_ref)
+
+ def _authenticate_local(self, context, auth):
+ """Try to authenticate against the identity backend.
+
+ Returns auth_token_data, (user_ref, tenant_ref, metadata_ref)
+ """
+ if 'passwordCredentials' not in auth:
+ raise exception.ValidationError(
+ attribute='passwordCredentials', target='auth')
+
+ if "password" not in auth['passwordCredentials']:
+ raise exception.ValidationError(
+ attribute='password', target='passwordCredentials')
+
+ password = auth['passwordCredentials']['password']
+
+ if ("userId" not in auth['passwordCredentials'] and
+ "username" not in auth['passwordCredentials']):
+ raise exception.ValidationError(
+ attribute='username or userId',
+ target='passwordCredentials')
+
+ user_id = auth['passwordCredentials'].get('userId', None)
+ username = auth['passwordCredentials'].get('username', '')
+
+ if username:
+ try:
+ user_ref = self.identity_api.get_user_by_name(
+ context=context, user_name=username)
+ user_id = user_ref['id']
+ except exception.UserNotFound:
+ LOG.warn("User not found: %s" % user_id)
+ raise exception.Unauthorized()
+
+ tenant_id = self._get_tenant_id_from_auth(context, auth)
+
+ try:
+ auth_info = self.identity_api.authenticate(
+ context=context,
+ user_id=user_id,
+ password=password,
+ tenant_id=tenant_id)
+ except AssertionError as e:
+ raise exception.Unauthorized(str(e))
+ (user_ref, tenant_ref, metadata_ref) = auth_info
+
+ expiry = self.token_api._get_default_expire_time(context=context)
+ auth_token_data = self._get_auth_token_data(user_ref,
+ tenant_ref,
+ metadata_ref,
+ expiry)
+
+ return auth_token_data, (user_ref, tenant_ref, metadata_ref)
+
+ def _authenticate_external(self, context, auth):
+ """Try to authenticate an external user via REMOTE_USER variable.
+
+ Returns auth_token_data, (user_ref, tenant_ref, metadata_ref)
+ """
+ if 'REMOTE_USER' not in context:
+ raise ExternalAuthNotApplicable()
+
+ username = context['REMOTE_USER']
+ try:
+ user_ref = self.identity_api.get_user_by_name(
+ context=context, user_name=username)
+ user_id = user_ref['id']
+ except exception.UserNotFound:
+ LOG.warn("User not found: %s" % username)
+ raise exception.Unauthorized()
+
+ tenant_id = self._get_tenant_id_from_auth(context, auth)
+
+ tenant_ref = self._get_tenant_ref(context, user_id, tenant_id)
+ metadata_ref = self._get_metadata_ref(context, user_id, tenant_id)
+
+ expiry = self.token_api._get_default_expire_time(context=context)
+ auth_token_data = self._get_auth_token_data(user_ref,
+ tenant_ref,
+ metadata_ref,
+ expiry)
+
+ return auth_token_data, (user_ref, tenant_ref, metadata_ref)
+
+ def _get_auth_token_data(self, user, tenant, metadata, expiry):
+ return dict(dict(user=user,
+ tenant=tenant,
+ metadata=metadata,
+ expires=expiry))
+
+ def _get_tenant_id_from_auth(self, context, auth):
+ """Extract tenant information from auth dict.
+
+ Returns a valid tenant_id if it exists, or None if not specified.
+ """
+ tenant_id = auth.get('tenantId', None)
+ tenant_name = auth.get('tenantName', None)
+ if tenant_name:
+ try:
+ tenant_ref = self.identity_api.get_tenant_by_name(
+ context=context, tenant_name=tenant_name)
+ tenant_id = tenant_ref['id']
+ except exception.TenantNotFound:
+ raise exception.Unauthorized()
+ return tenant_id
+
+ def _get_tenant_ref(self, context, user_id, tenant_id):
+ """Returns the tenant_ref for the user's tenant"""
+ tenant_ref = None
+ if tenant_id:
+ tenants = self.identity_api.get_tenants_for_user(context, user_id)
+ if tenant_id not in tenants:
+ LOG.warning('User %s is unauthorized for tenant %s'
+ % (user_id, tenant_id))
+ raise exception.Unauthorized()
+
+ try:
+ tenant_ref = self.identity_api.get_tenant(context=context,
+ tenant_id=tenant_id)
+ except exception.TenantNotFound:
+ exception.Unauthorized()
+ return tenant_ref
+
+ def _get_metadata_ref(self, context, user_id, tenant_id):
+ """Returns the metadata_ref for a user in a tenant"""
+ metadata_ref = {}
+ if tenant_id:
+ try:
+ metadata_ref = self.identity_api.get_metadata(
+ context=context,
+ user_id=user_id,
+ tenant_id=tenant_id)
+ except exception.MetadataNotFound:
+ metadata_ref = {}
+
+ return metadata_ref
+
def _get_token_ref(self, context, token_id, belongs_to=None):
"""Returns a token if a valid one exists.