From 920a49cfa055733d575282973e23558c33087a4a Mon Sep 17 00:00:00 2001 From: RHE Date: Fri, 24 Nov 2017 13:54:26 +0100 Subject: remove keystone-moon Change-Id: I80d7c9b669f19d5f6607e162de8e0e55c2f80fdd Signed-off-by: RHE --- keystone-moon/keystone/auth/__init__.py | 16 - keystone-moon/keystone/auth/controllers.py | 675 ------------------------ keystone-moon/keystone/auth/core.py | 94 ---- keystone-moon/keystone/auth/plugins/__init__.py | 15 - keystone-moon/keystone/auth/plugins/core.py | 211 -------- keystone-moon/keystone/auth/plugins/external.py | 101 ---- keystone-moon/keystone/auth/plugins/mapped.py | 258 --------- keystone-moon/keystone/auth/plugins/oauth1.py | 64 --- keystone-moon/keystone/auth/plugins/password.py | 42 -- keystone-moon/keystone/auth/plugins/saml2.py | 35 -- keystone-moon/keystone/auth/plugins/token.py | 97 ---- keystone-moon/keystone/auth/plugins/totp.py | 99 ---- keystone-moon/keystone/auth/routers.py | 57 -- 13 files changed, 1764 deletions(-) delete mode 100644 keystone-moon/keystone/auth/__init__.py delete mode 100644 keystone-moon/keystone/auth/controllers.py delete mode 100644 keystone-moon/keystone/auth/core.py delete mode 100644 keystone-moon/keystone/auth/plugins/__init__.py delete mode 100644 keystone-moon/keystone/auth/plugins/core.py delete mode 100644 keystone-moon/keystone/auth/plugins/external.py delete mode 100644 keystone-moon/keystone/auth/plugins/mapped.py delete mode 100644 keystone-moon/keystone/auth/plugins/oauth1.py delete mode 100644 keystone-moon/keystone/auth/plugins/password.py delete mode 100644 keystone-moon/keystone/auth/plugins/saml2.py delete mode 100644 keystone-moon/keystone/auth/plugins/token.py delete mode 100644 keystone-moon/keystone/auth/plugins/totp.py delete mode 100644 keystone-moon/keystone/auth/routers.py (limited to 'keystone-moon/keystone/auth') 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')) -- cgit 1.2.3-korg