aboutsummaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/token/controllers.py
diff options
context:
space:
mode:
Diffstat (limited to 'keystone-moon/keystone/token/controllers.py')
-rw-r--r--keystone-moon/keystone/token/controllers.py529
1 files changed, 0 insertions, 529 deletions
diff --git a/keystone-moon/keystone/token/controllers.py b/keystone-moon/keystone/token/controllers.py
deleted file mode 100644
index 6eeb23ec..00000000
--- a/keystone-moon/keystone/token/controllers.py
+++ /dev/null
@@ -1,529 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import datetime
-import sys
-
-from keystone.common import utils
-from keystoneclient.common import cms
-from oslo_config import cfg
-from oslo_log import log
-from oslo_serialization import jsonutils
-from oslo_utils import timeutils
-import six
-
-from keystone.common import controller
-from keystone.common import dependency
-from keystone.common import wsgi
-from keystone import exception
-from keystone.i18n import _
-from keystone.models import token_model
-from keystone.token import provider
-
-
-CONF = cfg.CONF
-LOG = log.getLogger(__name__)
-
-
-class ExternalAuthNotApplicable(Exception):
- """External authentication is not applicable."""
-
- pass
-
-
-@dependency.requires('assignment_api', 'catalog_api', 'identity_api',
- 'resource_api', 'role_api', 'token_provider_api',
- 'trust_api')
-class Auth(controller.V2Controller):
-
- @controller.v2_deprecated
- def ca_cert(self, context, auth=None):
- with open(CONF.signing.ca_certs, 'r') as ca_file:
- data = ca_file.read()
- return data
-
- @controller.v2_deprecated
- def signing_cert(self, context, auth=None):
- with open(CONF.signing.certfile, 'r') as cert_file:
- data = cert_file.read()
- return data
-
- @controller.v2_auth_deprecated
- def authenticate(self, context, auth=None):
- """Authenticate credentials and return a token.
-
- Accept auth as a dict that looks like::
-
- {
- "auth":{
- "passwordCredentials":{
- "username":"test_user",
- "password":"mypass"
- },
- "tenantName":"customer-x"
- }
- }
-
- In this case, tenant is optional, if not provided the token will be
- considered "unscoped" and can later be used to get a scoped token.
-
- Alternatively, this call accepts auth with only a token and tenant
- that will return a token that is scoped to that tenant.
- """
- if auth is None:
- raise exception.ValidationError(attribute='auth',
- target='request body')
-
- if "token" in auth:
- # Try to authenticate using a token
- auth_info = self._authenticate_token(
- context, auth)
- else:
- # Try external authentication
- try:
- auth_info = self._authenticate_external(
- context, auth)
- except ExternalAuthNotApplicable:
- # Try local authentication
- auth_info = self._authenticate_local(
- context, auth)
-
- user_ref, tenant_ref, metadata_ref, expiry, bind, audit_id = auth_info
- # Validate that the auth info is valid and nothing is disabled
- try:
- self.identity_api.assert_user_enabled(
- user_id=user_ref['id'], user=user_ref)
- if tenant_ref:
- self.resource_api.assert_project_enabled(
- project_id=tenant_ref['id'], project=tenant_ref)
- except AssertionError as e:
- six.reraise(exception.Unauthorized, exception.Unauthorized(e),
- sys.exc_info()[2])
- # NOTE(morganfainberg): Make sure the data is in correct form since it
- # might be consumed external to Keystone and this is a v2.0 controller.
- # The user_ref is encoded into the auth_token_data which is returned as
- # part of the token data. The token provider doesn't care about the
- # format.
- user_ref = self.v3_to_v2_user(user_ref)
- if tenant_ref:
- tenant_ref = self.v3_to_v2_project(tenant_ref)
-
- auth_token_data = self._get_auth_token_data(user_ref,
- tenant_ref,
- metadata_ref,
- expiry,
- audit_id)
-
- if tenant_ref:
- catalog_ref = self.catalog_api.get_catalog(
- user_ref['id'], tenant_ref['id'])
- else:
- catalog_ref = {}
-
- auth_token_data['id'] = 'placeholder'
- if bind:
- auth_token_data['bind'] = bind
-
- roles_ref = []
- for role_id in metadata_ref.get('roles', []):
- role_ref = self.role_api.get_role(role_id)
- roles_ref.append(dict(name=role_ref['name']))
-
- (token_id, token_data) = self.token_provider_api.issue_v2_token(
- auth_token_data, roles_ref=roles_ref, catalog_ref=catalog_ref)
-
- # NOTE(wanghong): We consume a trust use only when we are using trusts
- # and have successfully issued a token.
- if CONF.trust.enabled and 'trust_id' in auth:
- self.trust_api.consume_use(auth['trust_id'])
-
- return token_data
-
- def _restrict_scope(self, token_model_ref):
- # A trust token cannot be used to get another token
- if token_model_ref.trust_scoped:
- raise exception.Forbidden()
- if not CONF.token.allow_rescope_scoped_token:
- # Do not allow conversion from scoped tokens.
- if token_model_ref.project_scoped or token_model_ref.domain_scoped:
- raise exception.Forbidden(action=_("rescope a scoped token"))
-
- 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']
- if len(old_token) > CONF.max_token_size:
- raise exception.ValidationSizeError(attribute='token',
- size=CONF.max_token_size)
-
- try:
- token_model_ref = token_model.KeystoneToken(
- token_id=old_token,
- token_data=self.token_provider_api.validate_v2_token(old_token)
- )
- except exception.NotFound as e:
- raise exception.Unauthorized(e)
-
- wsgi.validate_token_bind(context, token_model_ref)
-
- self._restrict_scope(token_model_ref)
- user_id = token_model_ref.user_id
- tenant_id = self._get_project_id_from_auth(auth)
-
- if not CONF.trust.enabled and 'trust_id' in auth:
- raise exception.Forbidden('Trusts are disabled.')
- elif CONF.trust.enabled and 'trust_id' in auth:
- try:
- trust_ref = self.trust_api.get_trust(auth['trust_id'])
- except exception.TrustNotFound:
- raise exception.Forbidden()
- if user_id != trust_ref['trustee_user_id']:
- raise exception.Forbidden()
- if (trust_ref['project_id'] and
- tenant_id != trust_ref['project_id']):
- raise exception.Forbidden()
- if ('expires' in trust_ref) and (trust_ref['expires']):
- expiry = trust_ref['expires']
- if expiry < timeutils.parse_isotime(utils.isotime()):
- raise exception.Forbidden()
- user_id = trust_ref['trustor_user_id']
- trustor_user_ref = self.identity_api.get_user(
- trust_ref['trustor_user_id'])
- if not trustor_user_ref['enabled']:
- raise exception.Forbidden()
- trustee_user_ref = self.identity_api.get_user(
- trust_ref['trustee_user_id'])
- if not trustee_user_ref['enabled']:
- raise exception.Forbidden()
-
- if trust_ref['impersonation'] is True:
- current_user_ref = trustor_user_ref
- else:
- current_user_ref = trustee_user_ref
-
- else:
- current_user_ref = self.identity_api.get_user(user_id)
-
- metadata_ref = {}
- tenant_ref, metadata_ref['roles'] = self._get_project_roles_and_ref(
- user_id, tenant_id)
-
- expiry = token_model_ref.expires
- if CONF.trust.enabled and 'trust_id' in auth:
- trust_id = auth['trust_id']
- trust_roles = []
- for role in trust_ref['roles']:
- if 'roles' not in metadata_ref:
- raise exception.Forbidden()
- if role['id'] in metadata_ref['roles']:
- trust_roles.append(role['id'])
- else:
- raise exception.Forbidden()
- if 'expiry' in trust_ref and trust_ref['expiry']:
- trust_expiry = timeutils.parse_isotime(trust_ref['expiry'])
- if trust_expiry < expiry:
- expiry = trust_expiry
- metadata_ref['roles'] = trust_roles
- metadata_ref['trustee_user_id'] = trust_ref['trustee_user_id']
- metadata_ref['trust_id'] = trust_id
-
- bind = token_model_ref.bind
- audit_id = token_model_ref.audit_chain_id
-
- return (current_user_ref, tenant_ref, metadata_ref, expiry, bind,
- audit_id)
-
- 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 password and len(password) > CONF.identity.max_password_length:
- raise exception.ValidationSizeError(
- attribute='password', size=CONF.identity.max_password_length)
-
- if (not auth['passwordCredentials'].get("userId") and
- not auth['passwordCredentials'].get("username")):
- raise exception.ValidationError(
- attribute='username or userId',
- target='passwordCredentials')
-
- user_id = auth['passwordCredentials'].get('userId')
- if user_id and len(user_id) > CONF.max_param_size:
- raise exception.ValidationSizeError(attribute='userId',
- size=CONF.max_param_size)
-
- username = auth['passwordCredentials'].get('username', '')
-
- if username:
- if len(username) > CONF.max_param_size:
- raise exception.ValidationSizeError(attribute='username',
- size=CONF.max_param_size)
- try:
- user_ref = self.identity_api.get_user_by_name(
- username, CONF.identity.default_domain_id)
- user_id = user_ref['id']
- except exception.UserNotFound as e:
- raise exception.Unauthorized(e)
-
- try:
- user_ref = self.identity_api.authenticate(
- context,
- user_id=user_id,
- password=password)
- except AssertionError as e:
- raise exception.Unauthorized(e.args[0])
-
- metadata_ref = {}
- tenant_id = self._get_project_id_from_auth(auth)
- tenant_ref, metadata_ref['roles'] = self._get_project_roles_and_ref(
- user_id, tenant_id)
-
- expiry = provider.default_expire_time()
- bind = None
- audit_id = None
- return (user_ref, tenant_ref, metadata_ref, expiry, bind, audit_id)
-
- 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)
- """
- environment = context.get('environment', {})
- if not environment.get('REMOTE_USER'):
- raise ExternalAuthNotApplicable()
-
- username = environment['REMOTE_USER']
- try:
- user_ref = self.identity_api.get_user_by_name(
- username, CONF.identity.default_domain_id)
- user_id = user_ref['id']
- except exception.UserNotFound as e:
- raise exception.Unauthorized(e)
-
- metadata_ref = {}
- tenant_id = self._get_project_id_from_auth(auth)
- tenant_ref, metadata_ref['roles'] = self._get_project_roles_and_ref(
- user_id, tenant_id)
-
- expiry = provider.default_expire_time()
- bind = None
- if ('kerberos' in CONF.token.bind and
- environment.get('AUTH_TYPE', '').lower() == 'negotiate'):
- bind = {'kerberos': username}
- audit_id = None
-
- return (user_ref, tenant_ref, metadata_ref, expiry, bind, audit_id)
-
- def _get_auth_token_data(self, user, tenant, metadata, expiry, audit_id):
- return dict(user=user,
- tenant=tenant,
- metadata=metadata,
- expires=expiry,
- parent_audit_id=audit_id)
-
- def _get_project_id_from_auth(self, 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')
- if tenant_id and len(tenant_id) > CONF.max_param_size:
- raise exception.ValidationSizeError(attribute='tenantId',
- size=CONF.max_param_size)
-
- tenant_name = auth.get('tenantName')
- if tenant_name and len(tenant_name) > CONF.max_param_size:
- raise exception.ValidationSizeError(attribute='tenantName',
- size=CONF.max_param_size)
-
- if tenant_name:
- if (CONF.resource.project_name_url_safe == 'strict' and
- utils.is_not_url_safe(tenant_name)):
- msg = _('Tenant name cannot contain reserved characters.')
- raise exception.Unauthorized(message=msg)
- try:
- tenant_ref = self.resource_api.get_project_by_name(
- tenant_name, CONF.identity.default_domain_id)
- tenant_id = tenant_ref['id']
- except exception.ProjectNotFound as e:
- raise exception.Unauthorized(e)
- return tenant_id
-
- def _get_project_roles_and_ref(self, user_id, tenant_id):
- """Returns the project roles for this user, and the project ref."""
- tenant_ref = None
- role_list = []
- if tenant_id:
- try:
- tenant_ref = self.resource_api.get_project(tenant_id)
- role_list = self.assignment_api.get_roles_for_user_and_project(
- user_id, tenant_id)
- except exception.ProjectNotFound:
- msg = _('Project ID not found: %(t_id)s') % {'t_id': tenant_id}
- raise exception.Unauthorized(msg)
-
- if not role_list:
- msg = _('User %(u_id)s is unauthorized for tenant %(t_id)s')
- msg = msg % {'u_id': user_id, 't_id': tenant_id}
- LOG.warning(msg)
- raise exception.Unauthorized(msg)
-
- return (tenant_ref, role_list)
-
- def _get_token_ref(self, token_id, belongs_to=None):
- """Returns a token if a valid one exists.
-
- Optionally, limited to a token owned by a specific tenant.
-
- """
- token_ref = token_model.KeystoneToken(
- token_id=token_id,
- token_data=self.token_provider_api.validate_token(token_id))
- if belongs_to:
- if not token_ref.project_scoped:
- raise exception.Unauthorized(
- _('Token does not belong to specified tenant.'))
- if token_ref.project_id != belongs_to:
- raise exception.Unauthorized(
- _('Token does not belong to specified tenant.'))
- return token_ref
-
- @controller.v2_deprecated
- @controller.protected()
- def validate_token_head(self, context, token_id):
- """Check that a token is valid.
-
- Optionally, also ensure that it is owned by a specific tenant.
-
- Identical to ``validate_token``, except does not return a response.
-
- The code in ``keystone.common.wsgi.render_response`` will remove
- the content body.
-
- """
- belongs_to = context['query_string'].get('belongsTo')
- return self.token_provider_api.validate_v2_token(token_id, belongs_to)
-
- @controller.v2_deprecated
- @controller.protected()
- def validate_token(self, context, token_id):
- """Check that a token is valid.
-
- Optionally, also ensure that it is owned by a specific tenant.
-
- Returns metadata about the token along any associated roles.
-
- """
- belongs_to = context['query_string'].get('belongsTo')
- # TODO(ayoung) validate against revocation API
- return self.token_provider_api.validate_v2_token(token_id, belongs_to)
-
- @controller.v2_deprecated
- def delete_token(self, context, token_id):
- """Delete a token, effectively invalidating it for authz."""
- # TODO(termie): this stuff should probably be moved to middleware
- self.assert_admin(context)
- self.token_provider_api.revoke_token(token_id)
-
- @controller.v2_deprecated
- @controller.protected()
- def revocation_list(self, context, auth=None):
- if not CONF.token.revoke_by_id:
- raise exception.Gone()
- tokens = self.token_provider_api.list_revoked_tokens()
-
- for t in tokens:
- expires = t['expires']
- if expires and isinstance(expires, datetime.datetime):
- t['expires'] = utils.isotime(expires)
- data = {'revoked': tokens}
- json_data = jsonutils.dumps(data)
- signed_text = cms.cms_sign_text(json_data,
- CONF.signing.certfile,
- CONF.signing.keyfile)
-
- return {'signed': signed_text}
-
- @controller.v2_deprecated
- def endpoints(self, context, token_id):
- """Return a list of endpoints available to the token."""
- self.assert_admin(context)
-
- token_ref = self._get_token_ref(token_id)
-
- catalog_ref = None
- if token_ref.project_id:
- catalog_ref = self.catalog_api.get_catalog(
- token_ref.user_id,
- token_ref.project_id)
-
- return Auth.format_endpoint_list(catalog_ref)
-
- @classmethod
- def format_endpoint_list(cls, catalog_ref):
- """Formats a list of endpoints according to Identity API v2.
-
- The v2.0 API wants an endpoint list to look like::
-
- {
- 'endpoints': [
- {
- 'id': $endpoint_id,
- 'name': $SERVICE[name],
- 'type': $SERVICE,
- 'tenantId': $tenant_id,
- 'region': $REGION,
- }
- ],
- 'endpoints_links': [],
- }
-
- """
- if not catalog_ref:
- return {}
-
- endpoints = []
- for region_name, region_ref in catalog_ref.items():
- for service_type, service_ref in region_ref.items():
- endpoints.append({
- 'id': service_ref.get('id'),
- 'name': service_ref.get('name'),
- 'type': service_type,
- 'region': region_name,
- 'publicURL': service_ref.get('publicURL'),
- 'internalURL': service_ref.get('internalURL'),
- 'adminURL': service_ref.get('adminURL'),
- })
-
- return {'endpoints': endpoints, 'endpoints_links': []}