diff options
Diffstat (limited to 'keystone-moon/keystone/auth/plugins')
-rw-r--r-- | keystone-moon/keystone/auth/plugins/__init__.py | 15 | ||||
-rw-r--r-- | keystone-moon/keystone/auth/plugins/core.py | 211 | ||||
-rw-r--r-- | keystone-moon/keystone/auth/plugins/external.py | 101 | ||||
-rw-r--r-- | keystone-moon/keystone/auth/plugins/mapped.py | 258 | ||||
-rw-r--r-- | keystone-moon/keystone/auth/plugins/oauth1.py | 64 | ||||
-rw-r--r-- | keystone-moon/keystone/auth/plugins/password.py | 42 | ||||
-rw-r--r-- | keystone-moon/keystone/auth/plugins/saml2.py | 35 | ||||
-rw-r--r-- | keystone-moon/keystone/auth/plugins/token.py | 97 | ||||
-rw-r--r-- | keystone-moon/keystone/auth/plugins/totp.py | 99 |
9 files changed, 0 insertions, 922 deletions
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 |