aboutsummaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/auth
diff options
context:
space:
mode:
authorRHE <rebirthmonkey@gmail.com>2017-11-24 13:54:26 +0100
committerRHE <rebirthmonkey@gmail.com>2017-11-24 13:54:26 +0100
commit920a49cfa055733d575282973e23558c33087a4a (patch)
treed371dab34efa5028600dad2e7ca58063626e7ba4 /keystone-moon/keystone/auth
parentef3eefca70d8abb4a00dafb9419ad32738e934b2 (diff)
remove keystone-moon
Change-Id: I80d7c9b669f19d5f6607e162de8e0e55c2f80fdd Signed-off-by: RHE <rebirthmonkey@gmail.com>
Diffstat (limited to 'keystone-moon/keystone/auth')
-rw-r--r--keystone-moon/keystone/auth/__init__.py16
-rw-r--r--keystone-moon/keystone/auth/controllers.py675
-rw-r--r--keystone-moon/keystone/auth/core.py94
-rw-r--r--keystone-moon/keystone/auth/plugins/__init__.py15
-rw-r--r--keystone-moon/keystone/auth/plugins/core.py211
-rw-r--r--keystone-moon/keystone/auth/plugins/external.py101
-rw-r--r--keystone-moon/keystone/auth/plugins/mapped.py258
-rw-r--r--keystone-moon/keystone/auth/plugins/oauth1.py64
-rw-r--r--keystone-moon/keystone/auth/plugins/password.py42
-rw-r--r--keystone-moon/keystone/auth/plugins/saml2.py35
-rw-r--r--keystone-moon/keystone/auth/plugins/token.py97
-rw-r--r--keystone-moon/keystone/auth/plugins/totp.py99
-rw-r--r--keystone-moon/keystone/auth/routers.py57
13 files changed, 0 insertions, 1764 deletions
diff --git a/keystone-moon/keystone/auth/__init__.py b/keystone-moon/keystone/auth/__init__.py
deleted file mode 100644
index bcbf69fd..00000000
--- a/keystone-moon/keystone/auth/__init__.py
+++ /dev/null
@@ -1,16 +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.
-
-from keystone.auth import controllers # noqa
-from keystone.auth.core import * # noqa
diff --git a/keystone-moon/keystone/auth/controllers.py b/keystone-moon/keystone/auth/controllers.py
deleted file mode 100644
index 3e6af80f..00000000
--- a/keystone-moon/keystone/auth/controllers.py
+++ /dev/null
@@ -1,675 +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 sys
-
-from keystoneclient.common import cms
-from oslo_config import cfg
-from oslo_log import log
-from oslo_log import versionutils
-from oslo_serialization import jsonutils
-from oslo_utils import importutils
-import six
-import stevedore
-
-from keystone.common import config
-from keystone.common import controller
-from keystone.common import dependency
-from keystone.common import utils
-from keystone.common import wsgi
-from keystone import exception
-from keystone.federation import constants
-from keystone.i18n import _, _LI, _LW
-from keystone.resource import controllers as resource_controllers
-
-
-LOG = log.getLogger(__name__)
-
-CONF = cfg.CONF
-
-# registry of authentication methods
-AUTH_METHODS = {}
-AUTH_PLUGINS_LOADED = False
-
-
-def load_auth_method(method):
- plugin_name = CONF.auth.get(method) or 'default'
- namespace = 'keystone.auth.%s' % method
- try:
- driver_manager = stevedore.DriverManager(namespace, plugin_name,
- invoke_on_load=True)
- return driver_manager.driver
- except RuntimeError:
- LOG.debug('Failed to load the %s driver (%s) using stevedore, will '
- 'attempt to load using import_object instead.',
- method, plugin_name)
-
- driver = importutils.import_object(plugin_name)
-
- msg = (_(
- 'Direct import of auth plugin %(name)r is deprecated as of Liberty in '
- 'favor of its entrypoint from %(namespace)r and may be removed in '
- 'N.') %
- {'name': plugin_name, 'namespace': namespace})
- versionutils.report_deprecated_feature(LOG, msg)
-
- return driver
-
-
-def load_auth_methods():
- global AUTH_PLUGINS_LOADED
-
- if AUTH_PLUGINS_LOADED:
- # Only try and load methods a single time.
- return
- # config.setup_authentication should be idempotent, call it to ensure we
- # have setup all the appropriate configuration options we may need.
- config.setup_authentication()
- for plugin in set(CONF.auth.methods):
- AUTH_METHODS[plugin] = load_auth_method(plugin)
- AUTH_PLUGINS_LOADED = True
-
-
-def get_auth_method(method_name):
- global AUTH_METHODS
- if method_name not in AUTH_METHODS:
- raise exception.AuthMethodNotSupported()
- return AUTH_METHODS[method_name]
-
-
-class AuthContext(dict):
- """Retrofitting auth_context to reconcile identity attributes.
-
- The identity attributes must not have conflicting values among the
- auth plug-ins. The only exception is `expires_at`, which is set to its
- earliest value.
-
- """
-
- # identity attributes need to be reconciled among the auth plugins
- IDENTITY_ATTRIBUTES = frozenset(['user_id', 'project_id',
- 'access_token_id', 'domain_id',
- 'expires_at'])
-
- def __setitem__(self, key, val):
- if key in self.IDENTITY_ATTRIBUTES and key in self:
- existing_val = self[key]
- if key == 'expires_at':
- # special treatment for 'expires_at', we are going to take
- # the earliest expiration instead.
- if existing_val != val:
- LOG.info(_LI('"expires_at" has conflicting values '
- '%(existing)s and %(new)s. Will use the '
- 'earliest value.'),
- {'existing': existing_val, 'new': val})
- if existing_val is None or val is None:
- val = existing_val or val
- else:
- val = min(existing_val, val)
- elif existing_val != val:
- msg = _('Unable to reconcile identity attribute %(attribute)s '
- 'as it has conflicting values %(new)s and %(old)s') % (
- {'attribute': key,
- 'new': val,
- 'old': existing_val})
- raise exception.Unauthorized(msg)
- return super(AuthContext, self).__setitem__(key, val)
-
-
-@dependency.requires('resource_api', 'trust_api')
-class AuthInfo(object):
- """Encapsulation of "auth" request."""
-
- @staticmethod
- def create(context, auth=None, scope_only=False):
- auth_info = AuthInfo(context, auth=auth)
- auth_info._validate_and_normalize_auth_data(scope_only)
- return auth_info
-
- def __init__(self, context, auth=None):
- self.context = context
- self.auth = auth
- self._scope_data = (None, None, None, None)
- # self._scope_data is (domain_id, project_id, trust_ref, unscoped)
- # project scope: (None, project_id, None, None)
- # domain scope: (domain_id, None, None, None)
- # trust scope: (None, None, trust_ref, None)
- # unscoped: (None, None, None, 'unscoped')
-
- def _assert_project_is_enabled(self, project_ref):
- # ensure the project is enabled
- try:
- self.resource_api.assert_project_enabled(
- project_id=project_ref['id'],
- project=project_ref)
- except AssertionError as e:
- LOG.warning(six.text_type(e))
- six.reraise(exception.Unauthorized, exception.Unauthorized(e),
- sys.exc_info()[2])
-
- def _assert_domain_is_enabled(self, domain_ref):
- try:
- self.resource_api.assert_domain_enabled(
- domain_id=domain_ref['id'],
- domain=domain_ref)
- except AssertionError as e:
- LOG.warning(six.text_type(e))
- six.reraise(exception.Unauthorized, exception.Unauthorized(e),
- sys.exc_info()[2])
-
- def _lookup_domain(self, domain_info):
- domain_id = domain_info.get('id')
- domain_name = domain_info.get('name')
- domain_ref = None
- if not domain_id and not domain_name:
- raise exception.ValidationError(attribute='id or name',
- target='domain')
- try:
- if domain_name:
- if (CONF.resource.domain_name_url_safe == 'strict' and
- utils.is_not_url_safe(domain_name)):
- msg = _('Domain name cannot contain reserved characters.')
- raise exception.Unauthorized(message=msg)
- domain_ref = self.resource_api.get_domain_by_name(
- domain_name)
- else:
- domain_ref = self.resource_api.get_domain(domain_id)
- except exception.DomainNotFound as e:
- LOG.exception(six.text_type(e))
- raise exception.Unauthorized(e)
- self._assert_domain_is_enabled(domain_ref)
- return domain_ref
-
- def _lookup_project(self, project_info):
- project_id = project_info.get('id')
- project_name = project_info.get('name')
- project_ref = None
- if not project_id and not project_name:
- raise exception.ValidationError(attribute='id or name',
- target='project')
- try:
- if project_name:
- if (CONF.resource.project_name_url_safe == 'strict' and
- utils.is_not_url_safe(project_name)):
- msg = _('Project name cannot contain reserved characters.')
- raise exception.Unauthorized(message=msg)
- if 'domain' not in project_info:
- raise exception.ValidationError(attribute='domain',
- target='project')
- domain_ref = self._lookup_domain(project_info['domain'])
- project_ref = self.resource_api.get_project_by_name(
- project_name, domain_ref['id'])
- else:
- project_ref = self.resource_api.get_project(project_id)
- # NOTE(morganfainberg): The _lookup_domain method will raise
- # exception.Unauthorized if the domain isn't found or is
- # disabled.
- self._lookup_domain({'id': project_ref['domain_id']})
- except exception.ProjectNotFound as e:
- raise exception.Unauthorized(e)
- self._assert_project_is_enabled(project_ref)
- return project_ref
-
- def _lookup_trust(self, trust_info):
- trust_id = trust_info.get('id')
- if not trust_id:
- raise exception.ValidationError(attribute='trust_id',
- target='trust')
- trust = self.trust_api.get_trust(trust_id)
- return trust
-
- def _validate_and_normalize_scope_data(self):
- """Validate and normalize scope data."""
- if 'scope' not in self.auth:
- return
- if sum(['project' in self.auth['scope'],
- 'domain' in self.auth['scope'],
- 'unscoped' in self.auth['scope'],
- 'OS-TRUST:trust' in self.auth['scope']]) != 1:
- raise exception.ValidationError(
- attribute='project, domain, OS-TRUST:trust or unscoped',
- target='scope')
- if 'unscoped' in self.auth['scope']:
- self._scope_data = (None, None, None, 'unscoped')
- return
- if 'project' in self.auth['scope']:
- project_ref = self._lookup_project(self.auth['scope']['project'])
- self._scope_data = (None, project_ref['id'], None, None)
- elif 'domain' in self.auth['scope']:
- domain_ref = self._lookup_domain(self.auth['scope']['domain'])
- self._scope_data = (domain_ref['id'], None, None, None)
- elif 'OS-TRUST:trust' in self.auth['scope']:
- if not CONF.trust.enabled:
- raise exception.Forbidden('Trusts are disabled.')
- trust_ref = self._lookup_trust(
- self.auth['scope']['OS-TRUST:trust'])
- # TODO(ayoung): when trusts support domains, fill in domain data
- if trust_ref.get('project_id') is not None:
- project_ref = self._lookup_project(
- {'id': trust_ref['project_id']})
- self._scope_data = (None, project_ref['id'], trust_ref, None)
- else:
- self._scope_data = (None, None, trust_ref, None)
-
- def _validate_auth_methods(self):
- if 'identity' not in self.auth:
- raise exception.ValidationError(attribute='identity',
- target='auth')
-
- # make sure auth methods are provided
- if 'methods' not in self.auth['identity']:
- raise exception.ValidationError(attribute='methods',
- target='identity')
-
- # make sure all the method data/payload are provided
- for method_name in self.get_method_names():
- if method_name not in self.auth['identity']:
- raise exception.ValidationError(attribute=method_name,
- target='identity')
-
- # make sure auth method is supported
- for method_name in self.get_method_names():
- if method_name not in AUTH_METHODS:
- raise exception.AuthMethodNotSupported()
-
- def _validate_and_normalize_auth_data(self, scope_only=False):
- """Make sure "auth" is valid.
-
- :param scope_only: If it is True, auth methods will not be
- validated but only the scope data.
- :type scope_only: boolean
- """
- # make sure "auth" exist
- if not self.auth:
- raise exception.ValidationError(attribute='auth',
- target='request body')
-
- # NOTE(chioleong): Tokenless auth does not provide auth methods,
- # we only care about using this method to validate the scope
- # information. Therefore, validating the auth methods here is
- # insignificant and we can skip it when scope_only is set to
- # true.
- if scope_only is False:
- self._validate_auth_methods()
- self._validate_and_normalize_scope_data()
-
- def get_method_names(self):
- """Returns the identity method names.
-
- :returns: list of auth method names
-
- """
- # Sanitizes methods received in request's body
- # Filters out duplicates, while keeping elements' order.
- method_names = []
- for method in self.auth['identity']['methods']:
- if method not in method_names:
- method_names.append(method)
- return method_names
-
- def get_method_data(self, method):
- """Get the auth method payload.
-
- :returns: auth method payload
-
- """
- if method not in self.auth['identity']['methods']:
- raise exception.ValidationError(attribute=method,
- target='identity')
- return self.auth['identity'][method]
-
- def get_scope(self):
- """Get scope information.
-
- Verify and return the scoping information.
-
- :returns: (domain_id, project_id, trust_ref, unscoped).
- If scope to a project, (None, project_id, None, None)
- will be returned.
- If scoped to a domain, (domain_id, None, None, None)
- will be returned.
- If scoped to a trust, (None, project_id, trust_ref, None),
- Will be returned, where the project_id comes from the
- trust definition.
- If unscoped, (None, None, None, 'unscoped') will be
- returned.
-
- """
- return self._scope_data
-
- def set_scope(self, domain_id=None, project_id=None, trust=None,
- unscoped=None):
- """Set scope information."""
- if domain_id and project_id:
- msg = _('Scoping to both domain and project is not allowed')
- raise ValueError(msg)
- if domain_id and trust:
- msg = _('Scoping to both domain and trust is not allowed')
- raise ValueError(msg)
- if project_id and trust:
- msg = _('Scoping to both project and trust is not allowed')
- raise ValueError(msg)
- self._scope_data = (domain_id, project_id, trust, unscoped)
-
-
-@dependency.requires('assignment_api', 'catalog_api', 'identity_api',
- 'resource_api', 'token_provider_api', 'trust_api')
-class Auth(controller.V3Controller):
-
- # Note(atiwari): From V3 auth controller code we are
- # calling protection() wrappers, so we need to setup
- # the member_name and collection_name attributes of
- # auth controller code.
- # In the absence of these attributes, default 'entity'
- # string will be used to represent the target which is
- # generic. Policy can be defined using 'entity' but it
- # would not reflect the exact entity that is in context.
- # We are defining collection_name = 'tokens' and
- # member_name = 'token' to facilitate policy decisions.
- collection_name = 'tokens'
- member_name = 'token'
-
- def __init__(self, *args, **kw):
- super(Auth, self).__init__(*args, **kw)
- config.setup_authentication()
-
- def authenticate_for_token(self, context, auth=None):
- """Authenticate user and issue a token."""
- include_catalog = 'nocatalog' not in context['query_string']
-
- try:
- auth_info = AuthInfo.create(context, auth=auth)
- auth_context = AuthContext(extras={},
- method_names=[],
- bind={})
- self.authenticate(context, auth_info, auth_context)
- if auth_context.get('access_token_id'):
- auth_info.set_scope(None, auth_context['project_id'], None)
- self._check_and_set_default_scoping(auth_info, auth_context)
- (domain_id, project_id, trust, unscoped) = auth_info.get_scope()
-
- method_names = auth_info.get_method_names()
- method_names += auth_context.get('method_names', [])
- # make sure the list is unique
- method_names = list(set(method_names))
- expires_at = auth_context.get('expires_at')
- # NOTE(morganfainberg): define this here so it is clear what the
- # argument is during the issue_v3_token provider call.
- metadata_ref = None
-
- token_audit_id = auth_context.get('audit_id')
-
- (token_id, token_data) = self.token_provider_api.issue_v3_token(
- auth_context['user_id'], method_names, expires_at, project_id,
- domain_id, auth_context, trust, metadata_ref, include_catalog,
- parent_audit_id=token_audit_id)
-
- # NOTE(wanghong): We consume a trust use only when we are using
- # trusts and have successfully issued a token.
- if trust:
- self.trust_api.consume_use(trust['id'])
-
- return render_token_data_response(token_id, token_data,
- created=True)
- except exception.TrustNotFound as e:
- raise exception.Unauthorized(e)
-
- def _check_and_set_default_scoping(self, auth_info, auth_context):
- (domain_id, project_id, trust, unscoped) = auth_info.get_scope()
- if trust:
- project_id = trust['project_id']
- if domain_id or project_id or trust:
- # scope is specified
- return
-
- # Skip scoping when unscoped federated token is being issued
- if constants.IDENTITY_PROVIDER in auth_context:
- return
-
- # Do not scope if request is for explicitly unscoped token
- if unscoped is not None:
- return
-
- # fill in default_project_id if it is available
- try:
- user_ref = self.identity_api.get_user(auth_context['user_id'])
- except exception.UserNotFound as e:
- LOG.exception(six.text_type(e))
- raise exception.Unauthorized(e)
-
- default_project_id = user_ref.get('default_project_id')
- if not default_project_id:
- # User has no default project. He shall get an unscoped token.
- return
-
- # make sure user's default project is legit before scoping to it
- try:
- default_project_ref = self.resource_api.get_project(
- default_project_id)
- default_project_domain_ref = self.resource_api.get_domain(
- default_project_ref['domain_id'])
- if (default_project_ref.get('enabled', True) and
- default_project_domain_ref.get('enabled', True)):
- if self.assignment_api.get_roles_for_user_and_project(
- user_ref['id'], default_project_id):
- auth_info.set_scope(project_id=default_project_id)
- else:
- msg = _LW("User %(user_id)s doesn't have access to"
- " default project %(project_id)s. The token"
- " will be unscoped rather than scoped to the"
- " project.")
- LOG.warning(msg,
- {'user_id': user_ref['id'],
- 'project_id': default_project_id})
- else:
- msg = _LW("User %(user_id)s's default project %(project_id)s"
- " is disabled. The token will be unscoped rather"
- " than scoped to the project.")
- LOG.warning(msg,
- {'user_id': user_ref['id'],
- 'project_id': default_project_id})
- except (exception.ProjectNotFound, exception.DomainNotFound):
- # default project or default project domain doesn't exist,
- # will issue unscoped token instead
- msg = _LW("User %(user_id)s's default project %(project_id)s not"
- " found. The token will be unscoped rather than"
- " scoped to the project.")
- LOG.warning(msg, {'user_id': user_ref['id'],
- 'project_id': default_project_id})
-
- def authenticate(self, context, auth_info, auth_context):
- """Authenticate user."""
- # The 'external' method allows any 'REMOTE_USER' based authentication
- # In some cases the server can set REMOTE_USER as '' instead of
- # dropping it, so this must be filtered out
- if context['environment'].get('REMOTE_USER'):
- 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.
- LOG.debug("No 'external' plugin is registered.")
- except exception.Unauthorized:
- # If external fails then continue and attempt to determine
- # user identity using remaining auth methods
- LOG.debug("Authorization failed for 'external' auth method.")
-
- # need to aggregate the results in case two or more methods
- # are specified
- auth_response = {'methods': []}
- for method_name in auth_info.get_method_names():
- method = get_auth_method(method_name)
- resp = method.authenticate(context,
- auth_info.get_method_data(method_name),
- auth_context)
- if resp:
- auth_response['methods'].append(method_name)
- auth_response[method_name] = resp
-
- if auth_response["methods"]:
- # authentication continuation required
- raise exception.AdditionalAuthRequired(auth_response)
-
- if 'user_id' not in auth_context:
- msg = _('User not found')
- raise exception.Unauthorized(msg)
-
- @controller.protected()
- def check_token(self, context):
- token_id = context.get('subject_token_id')
- token_data = self.token_provider_api.validate_v3_token(
- token_id)
- # NOTE(morganfainberg): The code in
- # ``keystone.common.wsgi.render_response`` will remove the content
- # body.
- return render_token_data_response(token_id, token_data)
-
- @controller.protected()
- def revoke_token(self, context):
- token_id = context.get('subject_token_id')
- return self.token_provider_api.revoke_token(token_id)
-
- @controller.protected()
- def validate_token(self, context):
- token_id = context.get('subject_token_id')
- include_catalog = 'nocatalog' not in context['query_string']
- token_data = self.token_provider_api.validate_v3_token(
- token_id)
- if not include_catalog and 'catalog' in token_data['token']:
- del token_data['token']['catalog']
- return render_token_data_response(token_id, token_data)
-
- @controller.protected()
- def revocation_list(self, context, auth=None):
- if not CONF.token.revoke_by_id:
- raise exception.Gone()
-
- audit_id_only = ('audit_id_only' in context['query_string'])
-
- tokens = self.token_provider_api.list_revoked_tokens()
-
- for t in tokens:
- expires = t['expires']
- if not (expires and isinstance(expires, six.text_type)):
- t['expires'] = utils.isotime(expires)
- if audit_id_only:
- t.pop('id', None)
- data = {'revoked': tokens}
-
- if audit_id_only:
- # No need to obfuscate if no token IDs.
- return data
-
- json_data = jsonutils.dumps(data)
- signed_text = cms.cms_sign_text(json_data,
- CONF.signing.certfile,
- CONF.signing.keyfile)
-
- return {'signed': signed_text}
-
- def _combine_lists_uniquely(self, a, b):
- # it's most likely that only one of these will be filled so avoid
- # the combination if possible.
- if a and b:
- return {x['id']: x for x in a + b}.values()
- else:
- return a or b
-
- @controller.protected()
- def get_auth_projects(self, context):
- auth_context = self.get_auth_context(context)
-
- user_id = auth_context.get('user_id')
- user_refs = []
- if user_id:
- try:
- user_refs = self.assignment_api.list_projects_for_user(user_id)
- except exception.UserNotFound: # nosec
- # federated users have an id but they don't link to anything
- pass
-
- group_ids = auth_context.get('group_ids')
- grp_refs = []
- if group_ids:
- grp_refs = self.assignment_api.list_projects_for_groups(group_ids)
-
- refs = self._combine_lists_uniquely(user_refs, grp_refs)
- return resource_controllers.ProjectV3.wrap_collection(context, refs)
-
- @controller.protected()
- def get_auth_domains(self, context):
- auth_context = self.get_auth_context(context)
-
- user_id = auth_context.get('user_id')
- user_refs = []
- if user_id:
- try:
- user_refs = self.assignment_api.list_domains_for_user(user_id)
- except exception.UserNotFound: # nosec
- # federated users have an id but they don't link to anything
- pass
-
- group_ids = auth_context.get('group_ids')
- grp_refs = []
- if group_ids:
- grp_refs = self.assignment_api.list_domains_for_groups(group_ids)
-
- refs = self._combine_lists_uniquely(user_refs, grp_refs)
- return resource_controllers.DomainV3.wrap_collection(context, refs)
-
- @controller.protected()
- def get_auth_catalog(self, context):
- auth_context = self.get_auth_context(context)
- user_id = auth_context.get('user_id')
- project_id = auth_context.get('project_id')
-
- if not project_id:
- raise exception.Forbidden(
- _('A project-scoped token is required to produce a service '
- 'catalog.'))
-
- # The V3Controller base methods mostly assume that you're returning
- # either a collection or a single element from a collection, neither of
- # which apply to the catalog. Because this is a special case, this
- # re-implements a tiny bit of work done by the base controller (such as
- # self-referential link building) to avoid overriding or refactoring
- # several private methods.
- return {
- 'catalog': self.catalog_api.get_v3_catalog(user_id, project_id),
- 'links': {'self': self.base_url(context, path='auth/catalog')}
- }
-
-
-# FIXME(gyee): not sure if it belongs here or keystone.common. Park it here
-# for now.
-def render_token_data_response(token_id, token_data, created=False):
- """Render token data HTTP response.
-
- Stash token ID into the X-Subject-Token header.
-
- """
- headers = [('X-Subject-Token', token_id)]
-
- if created:
- status = (201, 'Created')
- else:
- status = (200, 'OK')
-
- return wsgi.render_response(body=token_data,
- status=status, headers=headers)
diff --git a/keystone-moon/keystone/auth/core.py b/keystone-moon/keystone/auth/core.py
deleted file mode 100644
index b865d82b..00000000
--- a/keystone-moon/keystone/auth/core.py
+++ /dev/null
@@ -1,94 +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 abc
-
-import six
-
-from keystone import exception
-
-
-@six.add_metaclass(abc.ABCMeta)
-class AuthMethodHandler(object):
- """Abstract base class for an authentication plugin."""
-
- def __init__(self):
- pass
-
- @abc.abstractmethod
- def authenticate(self, context, auth_payload, auth_context):
- """Authenticate user and return an authentication context.
-
- :param context: keystone's request context
- :param auth_payload: the content of the authentication for a given
- method
- :param auth_context: user authentication context, a dictionary shared
- by all plugins. It contains "method_names" and
- "extras" by default. "method_names" is a list and
- "extras" is a dictionary.
-
- If successful, plugin must set ``user_id`` in ``auth_context``.
- ``method_name`` is used to convey any additional authentication methods
- in case authentication is for re-scoping. For example, if the
- authentication is for re-scoping, plugin must append the previous
- method names into ``method_names``. Also, plugin may add any additional
- information into ``extras``. Anything in ``extras`` will be conveyed in
- the token's ``extras`` attribute. Here's an example of ``auth_context``
- on successful authentication::
-
- {
- "extras": {},
- "methods": [
- "password",
- "token"
- ],
- "user_id": "abc123"
- }
-
- Plugins are invoked in the order in which they are specified in the
- ``methods`` attribute of the ``identity`` object. For example,
- ``custom-plugin`` is invoked before ``password``, which is invoked
- before ``token`` in the following authentication request::
-
- {
- "auth": {
- "identity": {
- "custom-plugin": {
- "custom-data": "sdfdfsfsfsdfsf"
- },
- "methods": [
- "custom-plugin",
- "password",
- "token"
- ],
- "password": {
- "user": {
- "id": "s23sfad1",
- "password": "secrete"
- }
- },
- "token": {
- "id": "sdfafasdfsfasfasdfds"
- }
- }
- }
- }
-
- :returns: None if authentication is successful.
- Authentication payload in the form of a dictionary for the
- next authentication step if this is a multi step
- authentication.
- :raises keystone.exception.Unauthorized: for authentication failure
- """
- raise exception.Unauthorized()
diff --git a/keystone-moon/keystone/auth/plugins/__init__.py b/keystone-moon/keystone/auth/plugins/__init__.py
deleted file mode 100644
index 5da54703..00000000
--- a/keystone-moon/keystone/auth/plugins/__init__.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2015 CERN
-#
-# 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.
-
-from keystone.auth.plugins.core import * # noqa
diff --git a/keystone-moon/keystone/auth/plugins/core.py b/keystone-moon/keystone/auth/plugins/core.py
deleted file mode 100644
index c513f815..00000000
--- a/keystone-moon/keystone/auth/plugins/core.py
+++ /dev/null
@@ -1,211 +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 sys
-
-from oslo_config import cfg
-from oslo_log import log
-import six
-
-from keystone.common import dependency
-from keystone import exception
-
-
-CONF = cfg.CONF
-LOG = log.getLogger(__name__)
-
-
-def construct_method_map_from_config():
- """Determine authentication method types for deployment.
-
- :returns: a dictionary containing the methods and their indexes
-
- """
- method_map = dict()
- method_index = 1
- for method in CONF.auth.methods:
- method_map[method_index] = method
- method_index = method_index * 2
-
- return method_map
-
-
-def convert_method_list_to_integer(methods):
- """Convert the method type(s) to an integer.
-
- :param methods: a list of method names
- :returns: an integer representing the methods
-
- """
- method_map = construct_method_map_from_config()
-
- method_ints = []
- for method in methods:
- for k, v in method_map.items():
- if v == method:
- method_ints.append(k)
- return sum(method_ints)
-
-
-def convert_integer_to_method_list(method_int):
- """Convert an integer to a list of methods.
-
- :param method_int: an integer representing methods
- :returns: a corresponding list of methods
-
- """
- # If the method_int is 0 then no methods were used so return an empty
- # method list
- if method_int == 0:
- return []
-
- method_map = construct_method_map_from_config()
- method_ints = []
- for k, v in method_map.items():
- method_ints.append(k)
- method_ints.sort(reverse=True)
-
- confirmed_methods = []
- for m_int in method_ints:
- # (lbragstad): By dividing the method_int by each key in the
- # method_map, we know if the division results in an integer of 1, that
- # key was used in the construction of the total sum of the method_int.
- # In that case, we should confirm the key value and store it so we can
- # look it up later. Then we should take the remainder of what is
- # confirmed and the method_int and continue the process. In the end, we
- # should have a list of integers that correspond to indexes in our
- # method_map and we can reinflate the methods that the original
- # method_int represents.
- if (method_int / m_int) == 1:
- confirmed_methods.append(m_int)
- method_int = method_int - m_int
-
- methods = []
- for method in confirmed_methods:
- methods.append(method_map[method])
-
- return methods
-
-
-@dependency.requires('identity_api', 'resource_api')
-class BaseUserInfo(object):
-
- @classmethod
- def create(cls, auth_payload, method_name):
- user_auth_info = cls()
- user_auth_info._validate_and_normalize_auth_data(auth_payload)
- user_auth_info.METHOD_NAME = method_name
- return user_auth_info
-
- def __init__(self):
- self.user_id = None
- self.user_ref = None
- self.METHOD_NAME = None
-
- def _assert_domain_is_enabled(self, domain_ref):
- try:
- self.resource_api.assert_domain_enabled(
- domain_id=domain_ref['id'],
- domain=domain_ref)
- except AssertionError as e:
- LOG.warning(six.text_type(e))
- six.reraise(exception.Unauthorized, exception.Unauthorized(e),
- sys.exc_info()[2])
-
- def _assert_user_is_enabled(self, user_ref):
- try:
- self.identity_api.assert_user_enabled(
- user_id=user_ref['id'],
- user=user_ref)
- except AssertionError as e:
- LOG.warning(six.text_type(e))
- six.reraise(exception.Unauthorized, exception.Unauthorized(e),
- sys.exc_info()[2])
-
- def _lookup_domain(self, domain_info):
- domain_id = domain_info.get('id')
- domain_name = domain_info.get('name')
- domain_ref = None
- if not domain_id and not domain_name:
- raise exception.ValidationError(attribute='id or name',
- target='domain')
- try:
- if domain_name:
- domain_ref = self.resource_api.get_domain_by_name(
- domain_name)
- else:
- domain_ref = self.resource_api.get_domain(domain_id)
- except exception.DomainNotFound as e:
- LOG.exception(six.text_type(e))
- raise exception.Unauthorized(e)
- self._assert_domain_is_enabled(domain_ref)
- return domain_ref
-
- def _validate_and_normalize_auth_data(self, auth_payload):
- if 'user' not in auth_payload:
- raise exception.ValidationError(attribute='user',
- target=self.METHOD_NAME)
- user_info = auth_payload['user']
- user_id = user_info.get('id')
- user_name = user_info.get('name')
- user_ref = None
- if not user_id and not user_name:
- raise exception.ValidationError(attribute='id or name',
- target='user')
- try:
- if user_name:
- if 'domain' not in user_info:
- raise exception.ValidationError(attribute='domain',
- target='user')
- domain_ref = self._lookup_domain(user_info['domain'])
- user_ref = self.identity_api.get_user_by_name(
- user_name, domain_ref['id'])
- else:
- user_ref = self.identity_api.get_user(user_id)
- domain_ref = self.resource_api.get_domain(
- user_ref['domain_id'])
- self._assert_domain_is_enabled(domain_ref)
- except exception.UserNotFound as e:
- LOG.exception(six.text_type(e))
- raise exception.Unauthorized(e)
- self._assert_user_is_enabled(user_ref)
- self.user_ref = user_ref
- self.user_id = user_ref['id']
- self.domain_id = domain_ref['id']
-
-
-class UserAuthInfo(BaseUserInfo):
-
- def __init__(self):
- super(UserAuthInfo, self).__init__()
- self.password = None
-
- def _validate_and_normalize_auth_data(self, auth_payload):
- super(UserAuthInfo, self)._validate_and_normalize_auth_data(
- auth_payload)
- user_info = auth_payload['user']
- self.password = user_info.get('password')
-
-
-class TOTPUserInfo(BaseUserInfo):
-
- def __init__(self):
- super(TOTPUserInfo, self).__init__()
- self.passcode = None
-
- def _validate_and_normalize_auth_data(self, auth_payload):
- super(TOTPUserInfo, self)._validate_and_normalize_auth_data(
- auth_payload)
- user_info = auth_payload['user']
- self.passcode = user_info.get('passcode')
diff --git a/keystone-moon/keystone/auth/plugins/external.py b/keystone-moon/keystone/auth/plugins/external.py
deleted file mode 100644
index b00b808a..00000000
--- a/keystone-moon/keystone/auth/plugins/external.py
+++ /dev/null
@@ -1,101 +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.
-
-"""Keystone External Authentication Plugins"""
-
-import abc
-
-from oslo_config import cfg
-import six
-
-from keystone import auth
-from keystone.common import dependency
-from keystone import exception
-from keystone.i18n import _
-
-
-CONF = cfg.CONF
-
-
-@six.add_metaclass(abc.ABCMeta)
-class Base(auth.AuthMethodHandler):
- def authenticate(self, context, auth_info, auth_context):
- """Use REMOTE_USER to look up the user in the identity backend.
-
- auth_context is an in-out variable that will be updated with the
- user_id from the actual user from the REMOTE_USER env variable.
- """
- try:
- REMOTE_USER = context['environment']['REMOTE_USER']
- except KeyError:
- msg = _('No authenticated user')
- raise exception.Unauthorized(msg)
- try:
- user_ref = self._authenticate(REMOTE_USER, context)
- auth_context['user_id'] = user_ref['id']
- if ('kerberos' in CONF.token.bind and
- (context['environment'].get('AUTH_TYPE', '').lower()
- == 'negotiate')):
- auth_context['bind']['kerberos'] = user_ref['name']
- except Exception:
- msg = _('Unable to lookup user %s') % (REMOTE_USER)
- raise exception.Unauthorized(msg)
-
- @abc.abstractmethod
- def _authenticate(self, remote_user, context):
- """Look up the user in the identity backend.
-
- Return user_ref
- """
- pass
-
-
-@dependency.requires('identity_api')
-class DefaultDomain(Base):
- def _authenticate(self, remote_user, context):
- """Use remote_user to look up the user in the identity backend."""
- domain_id = CONF.identity.default_domain_id
- user_ref = self.identity_api.get_user_by_name(remote_user, domain_id)
- return user_ref
-
-
-@dependency.requires('identity_api', 'resource_api')
-class Domain(Base):
- def _authenticate(self, remote_user, context):
- """Use remote_user to look up the user in the identity backend.
-
- The domain will be extracted from the REMOTE_DOMAIN environment
- variable if present. If not, the default domain will be used.
- """
- username = remote_user
- try:
- domain_name = context['environment']['REMOTE_DOMAIN']
- except KeyError:
- domain_id = CONF.identity.default_domain_id
- else:
- domain_ref = self.resource_api.get_domain_by_name(domain_name)
- domain_id = domain_ref['id']
-
- user_ref = self.identity_api.get_user_by_name(username, domain_id)
- return user_ref
-
-
-class KerberosDomain(Domain):
- """Allows `kerberos` as a method."""
-
- 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)
diff --git a/keystone-moon/keystone/auth/plugins/mapped.py b/keystone-moon/keystone/auth/plugins/mapped.py
deleted file mode 100644
index e9716201..00000000
--- a/keystone-moon/keystone/auth/plugins/mapped.py
+++ /dev/null
@@ -1,258 +0,0 @@
-# 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 functools
-
-from pycadf import cadftaxonomy as taxonomy
-from six.moves.urllib import parse
-
-from keystone import auth
-from keystone.auth import plugins as auth_plugins
-from keystone.common import dependency
-from keystone import exception
-from keystone.federation import constants as federation_constants
-from keystone.federation import utils
-from keystone.i18n import _
-from keystone.models import token_model
-from keystone import notifications
-
-
-METHOD_NAME = 'mapped'
-
-
-@dependency.requires('federation_api', 'identity_api',
- 'resource_api', 'token_provider_api')
-class Mapped(auth.AuthMethodHandler):
-
- def _get_token_ref(self, auth_payload):
- token_id = auth_payload['id']
- response = self.token_provider_api.validate_token(token_id)
- return token_model.KeystoneToken(token_id=token_id,
- token_data=response)
-
- def authenticate(self, context, auth_payload, auth_context):
- """Authenticate mapped user and set an authentication context.
-
- :param context: keystone's request context
- :param auth_payload: the content of the authentication for a
- given method
- :param auth_context: user authentication context, a dictionary
- shared by all plugins.
-
- In addition to ``user_id`` in ``auth_context``, this plugin sets
- ``group_ids``, ``OS-FEDERATION:identity_provider`` and
- ``OS-FEDERATION:protocol``
-
- """
- if 'id' in auth_payload:
- token_ref = self._get_token_ref(auth_payload)
- handle_scoped_token(context, auth_payload, auth_context, token_ref,
- self.federation_api,
- self.identity_api,
- self.token_provider_api)
- else:
- handle_unscoped_token(context, auth_payload, auth_context,
- self.resource_api, self.federation_api,
- self.identity_api)
-
-
-def handle_scoped_token(context, auth_payload, auth_context, token_ref,
- federation_api, identity_api, token_provider_api):
- utils.validate_expiration(token_ref)
- token_audit_id = token_ref.audit_id
- identity_provider = token_ref.federation_idp_id
- protocol = token_ref.federation_protocol_id
- user_id = token_ref.user_id
- group_ids = token_ref.federation_group_ids
- send_notification = functools.partial(
- notifications.send_saml_audit_notification, 'authenticate',
- context, user_id, group_ids, identity_provider, protocol,
- token_audit_id)
-
- utils.assert_enabled_identity_provider(federation_api, identity_provider)
-
- try:
- mapping = federation_api.get_mapping_from_idp_and_protocol(
- identity_provider, protocol)
- utils.validate_groups(group_ids, mapping['id'], identity_api)
-
- except Exception:
- # NOTE(topol): Diaper defense to catch any exception, so we can
- # send off failed authentication notification, raise the exception
- # after sending the notification
- send_notification(taxonomy.OUTCOME_FAILURE)
- raise
- else:
- send_notification(taxonomy.OUTCOME_SUCCESS)
-
- auth_context['user_id'] = user_id
- auth_context['group_ids'] = group_ids
- auth_context[federation_constants.IDENTITY_PROVIDER] = identity_provider
- auth_context[federation_constants.PROTOCOL] = protocol
-
-
-def handle_unscoped_token(context, auth_payload, auth_context,
- resource_api, federation_api, identity_api):
-
- def is_ephemeral_user(mapped_properties):
- return mapped_properties['user']['type'] == utils.UserType.EPHEMERAL
-
- def build_ephemeral_user_context(auth_context, user, mapped_properties,
- identity_provider, protocol):
- auth_context['user_id'] = user['id']
- auth_context['group_ids'] = mapped_properties['group_ids']
- auth_context[federation_constants.IDENTITY_PROVIDER] = (
- identity_provider)
- auth_context[federation_constants.PROTOCOL] = protocol
-
- def build_local_user_context(auth_context, mapped_properties):
- user_info = auth_plugins.UserAuthInfo.create(mapped_properties,
- METHOD_NAME)
- auth_context['user_id'] = user_info.user_id
-
- assertion = extract_assertion_data(context)
- identity_provider = auth_payload['identity_provider']
- protocol = auth_payload['protocol']
-
- utils.assert_enabled_identity_provider(federation_api, identity_provider)
-
- group_ids = None
- # NOTE(topol): The user is coming in from an IdP with a SAML assertion
- # instead of from a token, so we set token_id to None
- token_id = None
- # NOTE(marek-denis): This variable is set to None and there is a
- # possibility that it will be used in the CADF notification. This means
- # operation will not be mapped to any user (even ephemeral).
- user_id = None
-
- try:
- try:
- mapped_properties, mapping_id = apply_mapping_filter(
- identity_provider, protocol, assertion, resource_api,
- federation_api, identity_api)
- except exception.ValidationError as e:
- # if mapping is either invalid or yield no valid identity,
- # it is considered a failed authentication
- raise exception.Unauthorized(e)
-
- if is_ephemeral_user(mapped_properties):
- unique_id, display_name = (
- get_user_unique_id_and_display_name(context, mapped_properties)
- )
- user = identity_api.shadow_federated_user(identity_provider,
- protocol, unique_id,
- display_name)
- user_id = user['id']
- group_ids = mapped_properties['group_ids']
- utils.validate_groups_cardinality(group_ids, mapping_id)
- build_ephemeral_user_context(auth_context, user,
- mapped_properties,
- identity_provider, protocol)
- else:
- build_local_user_context(auth_context, mapped_properties)
-
- except Exception:
- # NOTE(topol): Diaper defense to catch any exception, so we can
- # send off failed authentication notification, raise the exception
- # after sending the notification
- outcome = taxonomy.OUTCOME_FAILURE
- notifications.send_saml_audit_notification('authenticate', context,
- user_id, group_ids,
- identity_provider,
- protocol, token_id,
- outcome)
- raise
- else:
- outcome = taxonomy.OUTCOME_SUCCESS
- notifications.send_saml_audit_notification('authenticate', context,
- user_id, group_ids,
- identity_provider,
- protocol, token_id,
- outcome)
-
-
-def extract_assertion_data(context):
- assertion = dict(utils.get_assertion_params_from_env(context))
- return assertion
-
-
-def apply_mapping_filter(identity_provider, protocol, assertion,
- resource_api, federation_api, identity_api):
- idp = federation_api.get_idp(identity_provider)
- utils.validate_idp(idp, protocol, assertion)
-
- mapped_properties, mapping_id = federation_api.evaluate(
- identity_provider, protocol, assertion)
-
- # NOTE(marek-denis): We update group_ids only here to avoid fetching
- # groups identified by name/domain twice.
- # NOTE(marek-denis): Groups are translated from name/domain to their
- # corresponding ids in the auth plugin, as we need information what
- # ``mapping_id`` was used as well as idenity_api and resource_api
- # objects.
- group_ids = mapped_properties['group_ids']
- utils.validate_groups_in_backend(group_ids,
- mapping_id,
- identity_api)
- group_ids.extend(
- utils.transform_to_group_ids(
- mapped_properties['group_names'], mapping_id,
- identity_api, resource_api))
- mapped_properties['group_ids'] = list(set(group_ids))
- return mapped_properties, mapping_id
-
-
-def get_user_unique_id_and_display_name(context, mapped_properties):
- """Setup federated username.
-
- Function covers all the cases for properly setting user id, a primary
- identifier for identity objects. Initial version of the mapping engine
- assumed user is identified by ``name`` and his ``id`` is built from the
- name. We, however need to be able to accept local rules that identify user
- by either id or name/domain.
-
- The following use-cases are covered:
-
- 1) If neither user_name nor user_id is set raise exception.Unauthorized
- 2) If user_id is set and user_name not, set user_name equal to user_id
- 3) If user_id is not set and user_name is, set user_id as url safe version
- of user_name.
-
- :param context: authentication context
- :param mapped_properties: Properties issued by a RuleProcessor.
- :type: dictionary
-
- :raises keystone.exception.Unauthorized: If neither `user_name` nor
- `user_id` is set.
- :returns: tuple with user identification
- :rtype: tuple
-
- """
- user = mapped_properties['user']
-
- user_id = user.get('id')
- user_name = user.get('name') or context['environment'].get('REMOTE_USER')
-
- if not any([user_id, user_name]):
- msg = _("Could not map user while setting ephemeral user identity. "
- "Either mapping rules must specify user id/name or "
- "REMOTE_USER environment variable must be set.")
- raise exception.Unauthorized(msg)
-
- elif not user_name:
- user['name'] = user_id
-
- elif not user_id:
- user_id = user_name
-
- user['id'] = parse.quote(user_id)
- return (user['id'], user['name'])
diff --git a/keystone-moon/keystone/auth/plugins/oauth1.py b/keystone-moon/keystone/auth/plugins/oauth1.py
deleted file mode 100644
index bf60f91c..00000000
--- a/keystone-moon/keystone/auth/plugins/oauth1.py
+++ /dev/null
@@ -1,64 +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.
-
-from oslo_utils import timeutils
-
-from keystone import auth
-from keystone.common import controller
-from keystone.common import dependency
-from keystone import exception
-from keystone.i18n import _
-from keystone.oauth1 import core as oauth
-from keystone.oauth1 import validator
-
-
-@dependency.requires('oauth_api')
-class OAuth(auth.AuthMethodHandler):
- def authenticate(self, context, auth_info, auth_context):
- """Turn a signed request with an access key into a keystone token."""
- headers = context['headers']
- oauth_headers = oauth.get_oauth_headers(headers)
- access_token_id = oauth_headers.get('oauth_token')
-
- if not access_token_id:
- raise exception.ValidationError(
- attribute='oauth_token', target='request')
-
- acc_token = self.oauth_api.get_access_token(access_token_id)
-
- expires_at = acc_token['expires_at']
- if expires_at:
- now = timeutils.utcnow()
- expires = timeutils.normalize_time(
- timeutils.parse_isotime(expires_at))
- if now > expires:
- raise exception.Unauthorized(_('Access token is expired'))
-
- url = controller.V3Controller.base_url(context, context['path'])
- access_verifier = oauth.ResourceEndpoint(
- request_validator=validator.OAuthValidator(),
- token_generator=oauth.token_generator)
- result, request = access_verifier.validate_protected_resource_request(
- url,
- http_method='POST',
- body=context['query_string'],
- headers=headers,
- realms=None
- )
- if not result:
- msg = _('Could not validate the access token')
- raise exception.Unauthorized(msg)
- auth_context['user_id'] = acc_token['authorizing_user_id']
- auth_context['access_token_id'] = access_token_id
- auth_context['project_id'] = acc_token['project_id']
diff --git a/keystone-moon/keystone/auth/plugins/password.py b/keystone-moon/keystone/auth/plugins/password.py
deleted file mode 100644
index a16887b4..00000000
--- a/keystone-moon/keystone/auth/plugins/password.py
+++ /dev/null
@@ -1,42 +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.
-
-from keystone import auth
-from keystone.auth import plugins as auth_plugins
-from keystone.common import dependency
-from keystone import exception
-from keystone.i18n import _
-
-
-METHOD_NAME = 'password'
-
-
-@dependency.requires('identity_api')
-class Password(auth.AuthMethodHandler):
-
- def authenticate(self, context, auth_payload, auth_context):
- """Try to authenticate against the identity backend."""
- user_info = auth_plugins.UserAuthInfo.create(auth_payload, METHOD_NAME)
-
- try:
- self.identity_api.authenticate(
- context,
- user_id=user_info.user_id,
- password=user_info.password)
- except AssertionError:
- # authentication failed because of invalid username or password
- msg = _('Invalid username or password')
- raise exception.Unauthorized(msg)
-
- auth_context['user_id'] = user_info.user_id
diff --git a/keystone-moon/keystone/auth/plugins/saml2.py b/keystone-moon/keystone/auth/plugins/saml2.py
deleted file mode 100644
index 0e7ec6bc..00000000
--- a/keystone-moon/keystone/auth/plugins/saml2.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# 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.
-
-from oslo_log import versionutils
-
-from keystone.auth.plugins import mapped
-
-
-@versionutils.deprecated(
- versionutils.deprecated.MITAKA,
- what='keystone.auth.plugins.saml2.Saml2',
- in_favor_of='keystone.auth.plugins.mapped.Mapped',
- remove_in=+2)
-class Saml2(mapped.Mapped):
- """Provide an entry point to authenticate with SAML2.
-
- This plugin subclasses ``mapped.Mapped``, and may be specified in
- keystone.conf::
-
- [auth]
- methods = external,password,token,saml2
- saml2 = keystone.auth.plugins.mapped.Mapped
-
- """
-
- pass
diff --git a/keystone-moon/keystone/auth/plugins/token.py b/keystone-moon/keystone/auth/plugins/token.py
deleted file mode 100644
index 069f1140..00000000
--- a/keystone-moon/keystone/auth/plugins/token.py
+++ /dev/null
@@ -1,97 +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.
-
-from oslo_config import cfg
-from oslo_log import log
-import six
-
-from keystone import auth
-from keystone.auth.plugins import mapped
-from keystone.common import dependency
-from keystone.common import wsgi
-from keystone import exception
-from keystone.i18n import _
-from keystone.models import token_model
-
-
-LOG = log.getLogger(__name__)
-
-CONF = cfg.CONF
-
-
-@dependency.requires('federation_api', 'identity_api', 'token_provider_api')
-class Token(auth.AuthMethodHandler):
-
- def _get_token_ref(self, auth_payload):
- token_id = auth_payload['id']
- response = self.token_provider_api.validate_token(token_id)
- return token_model.KeystoneToken(token_id=token_id,
- token_data=response)
-
- def authenticate(self, context, auth_payload, user_context):
- if 'id' not in auth_payload:
- raise exception.ValidationError(attribute='id',
- target='token')
- token_ref = self._get_token_ref(auth_payload)
- if token_ref.is_federated_user and self.federation_api:
- mapped.handle_scoped_token(
- context, auth_payload, user_context, token_ref,
- self.federation_api, self.identity_api,
- self.token_provider_api)
- else:
- token_authenticate(context, auth_payload, user_context, token_ref)
-
-
-def token_authenticate(context, auth_payload, user_context, token_ref):
- try:
-
- # Do not allow tokens used for delegation to
- # create another token, or perform any changes of
- # state in Keystone. To do so is to invite elevation of
- # privilege attacks
-
- if token_ref.oauth_scoped or token_ref.trust_scoped:
- raise exception.Forbidden()
-
- if not CONF.token.allow_rescope_scoped_token:
- # Do not allow conversion from scoped tokens.
- if token_ref.project_scoped or token_ref.domain_scoped:
- raise exception.Forbidden(action=_("rescope a scoped token"))
-
- wsgi.validate_token_bind(context, token_ref)
-
- # New tokens maintain the audit_id of the original token in the
- # chain (if possible) as the second element in the audit data
- # structure. Look for the last element in the audit data structure
- # which will be either the audit_id of the token (in the case of
- # a token that has not been rescoped) or the audit_chain id (in
- # the case of a token that has been rescoped).
- try:
- token_audit_id = token_ref.get('audit_ids', [])[-1]
- except IndexError:
- # NOTE(morganfainberg): In the case this is a token that was
- # issued prior to audit id existing, the chain is not tracked.
- token_audit_id = None
-
- user_context.setdefault('expires_at', token_ref.expires)
- user_context['audit_id'] = token_audit_id
- user_context.setdefault('user_id', token_ref.user_id)
- # TODO(morganfainberg: determine if token 'extras' can be removed
- # from the user_context
- user_context['extras'].update(token_ref.get('extras', {}))
- user_context['method_names'].extend(token_ref.methods)
-
- except AssertionError as e:
- LOG.error(six.text_type(e))
- raise exception.Unauthorized(e)
diff --git a/keystone-moon/keystone/auth/plugins/totp.py b/keystone-moon/keystone/auth/plugins/totp.py
deleted file mode 100644
index d0b61b3b..00000000
--- a/keystone-moon/keystone/auth/plugins/totp.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# 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.
-
-"""Time-based One-time Password Algorithm (TOTP) auth plugin
-
-TOTP is an algorithm that computes a one-time password from a shared secret
-key and the current time.
-
-TOTP is an implementation of a hash-based message authentication code (HMAC).
-It combines a secret key with the current timestamp using a cryptographic hash
-function to generate a one-time password. The timestamp typically increases in
-30-second intervals, so passwords generated close together in time from the
-same secret key will be equal.
-"""
-
-import base64
-
-from cryptography.hazmat.backends import default_backend
-from cryptography.hazmat.primitives import hashes
-from cryptography.hazmat.primitives.twofactor import totp as crypto_totp
-from oslo_log import log
-from oslo_utils import timeutils
-import six
-
-from keystone import auth
-from keystone.auth import plugins
-from keystone.common import dependency
-from keystone import exception
-from keystone.i18n import _
-
-
-METHOD_NAME = 'totp'
-
-LOG = log.getLogger(__name__)
-
-
-def _generate_totp_passcode(secret):
- """Generate TOTP passcode.
-
- :param bytes secret: A base32 encoded secret for the TOTP authentication
- :returns: totp passcode as bytes
- """
- if isinstance(secret, six.text_type):
- # NOTE(dstanek): since this may be coming from the JSON stored in the
- # database it may be UTF-8 encoded
- secret = secret.encode('utf-8')
-
- # NOTE(nonameentername): cryptography takes a non base32 encoded value for
- # TOTP. Add the correct padding to be able to base32 decode
- while len(secret) % 8 != 0:
- secret = secret + b'='
-
- decoded = base64.b32decode(secret)
- totp = crypto_totp.TOTP(
- decoded, 6, hashes.SHA1(), 30, backend=default_backend())
- return totp.generate(timeutils.utcnow_ts(microsecond=True))
-
-
-@dependency.requires('credential_api')
-class TOTP(auth.AuthMethodHandler):
-
- def authenticate(self, context, auth_payload, auth_context):
- """Try to authenticate using TOTP"""
- user_info = plugins.TOTPUserInfo.create(auth_payload, METHOD_NAME)
- auth_passcode = auth_payload.get('user').get('passcode')
-
- credentials = self.credential_api.list_credentials_for_user(
- user_info.user_id, type='totp')
-
- valid_passcode = False
- for credential in credentials:
- try:
- generated_passcode = _generate_totp_passcode(
- credential['blob'])
- if auth_passcode == generated_passcode:
- valid_passcode = True
- break
- except (ValueError, KeyError):
- LOG.debug('No TOTP match; credential id: %s, user_id: %s',
- credential['id'], user_info.user_id)
- except (TypeError):
- LOG.debug('Base32 decode failed for TOTP credential %s',
- credential['id'])
-
- if not valid_passcode:
- # authentication failed because of invalid username or passcode
- msg = _('Invalid username or TOTP passcode')
- raise exception.Unauthorized(msg)
-
- auth_context['user_id'] = user_info.user_id
diff --git a/keystone-moon/keystone/auth/routers.py b/keystone-moon/keystone/auth/routers.py
deleted file mode 100644
index c7a525c3..00000000
--- a/keystone-moon/keystone/auth/routers.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2012 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.
-
-from keystone.auth import controllers
-from keystone.common import json_home
-from keystone.common import wsgi
-
-
-class Routers(wsgi.RoutersBase):
-
- def append_v3_routers(self, mapper, routers):
- auth_controller = controllers.Auth()
-
- self._add_resource(
- mapper, auth_controller,
- path='/auth/tokens',
- get_action='validate_token',
- head_action='check_token',
- post_action='authenticate_for_token',
- delete_action='revoke_token',
- rel=json_home.build_v3_resource_relation('auth_tokens'))
-
- self._add_resource(
- mapper, auth_controller,
- path='/auth/tokens/OS-PKI/revoked',
- get_action='revocation_list',
- rel=json_home.build_v3_extension_resource_relation(
- 'OS-PKI', '1.0', 'revocations'))
-
- self._add_resource(
- mapper, auth_controller,
- path='/auth/catalog',
- get_action='get_auth_catalog',
- rel=json_home.build_v3_resource_relation('auth_catalog'))
-
- self._add_resource(
- mapper, auth_controller,
- path='/auth/projects',
- get_action='get_auth_projects',
- rel=json_home.build_v3_resource_relation('auth_projects'))
-
- self._add_resource(
- mapper, auth_controller,
- path='/auth/domains',
- get_action='get_auth_domains',
- rel=json_home.build_v3_resource_relation('auth_domains'))