From 92fd2dbfb672d7b2b1cdfd5dd5cf89f7716b3e12 Mon Sep 17 00:00:00 2001 From: asteroide Date: Tue, 1 Sep 2015 16:03:26 +0200 Subject: Update Keystone code from official Github repository with branch Master on 09/01/2015. Change-Id: I0ff6099e6e2580f87f502002a998bbfe12673498 --- keystone-moon/keystone/auth/controllers.py | 63 +++++++++--------- keystone-moon/keystone/auth/plugins/core.py | 5 +- keystone-moon/keystone/auth/plugins/external.py | 85 ------------------------- keystone-moon/keystone/auth/plugins/mapped.py | 62 +++++++++--------- keystone-moon/keystone/auth/plugins/oauth1.py | 6 -- keystone-moon/keystone/auth/plugins/password.py | 5 +- keystone-moon/keystone/auth/plugins/saml2.py | 3 +- keystone-moon/keystone/auth/plugins/token.py | 4 +- 8 files changed, 68 insertions(+), 165 deletions(-) (limited to 'keystone-moon/keystone/auth') diff --git a/keystone-moon/keystone/auth/controllers.py b/keystone-moon/keystone/auth/controllers.py index 065f1f01..04124696 100644 --- a/keystone-moon/keystone/auth/controllers.py +++ b/keystone-moon/keystone/auth/controllers.py @@ -17,16 +17,18 @@ 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 -from oslo_utils import timeutils import six +import stevedore from keystone.common import controller from keystone.common import dependency +from keystone.common import utils from keystone.common import wsgi from keystone import config -from keystone.contrib import federation +from keystone.contrib.federation import constants as federation_constants from keystone import exception from keystone.i18n import _, _LI, _LW from keystone.resource import controllers as resource_controllers @@ -41,6 +43,27 @@ AUTH_METHODS = {} AUTH_PLUGINS_LOADED = False +def load_auth_method(method): + plugin_name = CONF.auth.get(method) or 'default' + try: + namespace = 'keystone.auth.%s' % method + 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) + + @versionutils.deprecated(as_of=versionutils.deprecated.LIBERTY, + in_favor_of='entrypoints', + what='direct import of driver') + def _load_using_import(plugin_name): + return importutils.import_object(plugin_name) + + return _load_using_import(plugin_name) + + def load_auth_methods(): global AUTH_PLUGINS_LOADED @@ -50,28 +73,8 @@ def load_auth_methods(): # 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 CONF.auth.methods: - if '.' in plugin: - # NOTE(morganfainberg): if '.' is in the plugin name, it should be - # imported rather than used as a plugin identifier. - plugin_class = plugin - driver = importutils.import_object(plugin) - if not hasattr(driver, 'method'): - raise ValueError(_('Cannot load an auth-plugin by class-name ' - 'without a "method" attribute defined: %s'), - plugin_class) - - LOG.info(_LI('Loading auth-plugins by class-name is deprecated.')) - plugin_name = driver.method - else: - plugin_name = plugin - plugin_class = CONF.auth.get(plugin) - driver = importutils.import_object(plugin_class) - if plugin_name in AUTH_METHODS: - raise ValueError(_('Auth plugin %(plugin)s is requesting ' - 'previously registered method %(method)s') % - {'plugin': plugin_class, 'method': driver.method}) - AUTH_METHODS[plugin_name] = driver + for plugin in set(CONF.auth.methods): + AUTH_METHODS[plugin] = load_auth_method(plugin) AUTH_PLUGINS_LOADED = True @@ -121,11 +124,7 @@ class AuthContext(dict): return super(AuthContext, self).__setitem__(key, val) -# TODO(blk-u): this class doesn't use identity_api directly, but makes it -# available for consumers. Consumers should probably not be getting -# identity_api from this since it's available in global registry, then -# identity_api should be removed from this list. -@dependency.requires('identity_api', 'resource_api', 'trust_api') +@dependency.requires('resource_api', 'trust_api') class AuthInfo(object): """Encapsulation of "auth" request.""" @@ -217,8 +216,6 @@ class AuthInfo(object): raise exception.ValidationError(attribute='trust_id', target='trust') trust = self.trust_api.get_trust(trust_id) - if not trust: - raise exception.TrustNotFound(trust_id=trust_id) return trust def _validate_and_normalize_scope_data(self): @@ -415,7 +412,7 @@ class Auth(controller.V3Controller): return # Skip scoping when unscoped federated token is being issued - if federation.IDENTITY_PROVIDER in auth_context: + if federation_constants.IDENTITY_PROVIDER in auth_context: return # Do not scope if request is for explicitly unscoped token @@ -546,7 +543,7 @@ class Auth(controller.V3Controller): for t in tokens: expires = t['expires'] if not (expires and isinstance(expires, six.text_type)): - t['expires'] = timeutils.isotime(expires) + t['expires'] = utils.isotime(expires) data = {'revoked': tokens} json_data = jsonutils.dumps(data) signed_text = cms.cms_sign_text(json_data, diff --git a/keystone-moon/keystone/auth/plugins/core.py b/keystone-moon/keystone/auth/plugins/core.py index 96a5ecf8..bcad27e5 100644 --- a/keystone-moon/keystone/auth/plugins/core.py +++ b/keystone-moon/keystone/auth/plugins/core.py @@ -21,6 +21,7 @@ import six from keystone.common import dependency from keystone import exception + CONF = cfg.CONF LOG = log.getLogger(__name__) @@ -51,7 +52,7 @@ def convert_method_list_to_integer(methods): method_ints = [] for method in methods: - for k, v in six.iteritems(method_map): + for k, v in method_map.items(): if v == method: method_ints.append(k) return sum(method_ints) @@ -71,7 +72,7 @@ def convert_integer_to_method_list(method_int): method_map = construct_method_map_from_config() method_ints = [] - for k, v in six.iteritems(method_map): + for k, v in method_map.items(): method_ints.append(k) method_ints.sort(reverse=True) diff --git a/keystone-moon/keystone/auth/plugins/external.py b/keystone-moon/keystone/auth/plugins/external.py index 2322649f..cabe6282 100644 --- a/keystone-moon/keystone/auth/plugins/external.py +++ b/keystone-moon/keystone/auth/plugins/external.py @@ -23,7 +23,6 @@ from keystone import auth from keystone.common import dependency from keystone import exception from keystone.i18n import _ -from keystone.openstack.common import versionutils CONF = cfg.CONF @@ -31,9 +30,6 @@ CONF = cfg.CONF @six.add_metaclass(abc.ABCMeta) class Base(auth.AuthMethodHandler): - - method = 'external' - def authenticate(self, context, auth_info, auth_context): """Use REMOTE_USER to look up the user in the identity backend. @@ -96,91 +92,10 @@ class Domain(Base): return user_ref -@dependency.requires('assignment_api', 'identity_api') class KerberosDomain(Domain): """Allows `kerberos` as a method.""" - method = 'kerberos' - 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) - - -class ExternalDefault(DefaultDomain): - """Deprecated. Please use keystone.auth.external.DefaultDomain instead.""" - - @versionutils.deprecated( - as_of=versionutils.deprecated.ICEHOUSE, - in_favor_of='keystone.auth.external.DefaultDomain', - remove_in=+1) - def __init__(self): - super(ExternalDefault, self).__init__() - - -class ExternalDomain(Domain): - """Deprecated. Please use keystone.auth.external.Domain instead.""" - - @versionutils.deprecated( - as_of=versionutils.deprecated.ICEHOUSE, - in_favor_of='keystone.auth.external.Domain', - remove_in=+1) - def __init__(self): - super(ExternalDomain, self).__init__() - - -@dependency.requires('identity_api') -class LegacyDefaultDomain(Base): - """Deprecated. Please use keystone.auth.external.DefaultDomain instead. - - This plugin exists to provide compatibility for the unintended behavior - described here: https://bugs.launchpad.net/keystone/+bug/1253484 - - """ - - @versionutils.deprecated( - as_of=versionutils.deprecated.ICEHOUSE, - in_favor_of='keystone.auth.external.DefaultDomain', - remove_in=+1) - def __init__(self): - super(LegacyDefaultDomain, self).__init__() - - def _authenticate(self, remote_user, context): - """Use remote_user to look up the user in the identity backend.""" - # NOTE(dolph): this unintentionally discards half the REMOTE_USER value - names = remote_user.split('@') - username = names.pop(0) - domain_id = CONF.identity.default_domain_id - user_ref = self.identity_api.get_user_by_name(username, domain_id) - return user_ref - - -@dependency.requires('identity_api', 'resource_api') -class LegacyDomain(Base): - """Deprecated. Please use keystone.auth.external.Domain instead.""" - - @versionutils.deprecated( - as_of=versionutils.deprecated.ICEHOUSE, - in_favor_of='keystone.auth.external.Domain', - remove_in=+1) - def __init__(self): - super(LegacyDomain, self).__init__() - - def _authenticate(self, remote_user, context): - """Use remote_user to look up the user in the identity backend. - - If remote_user contains an `@` assume that the substring before the - rightmost `@` is the username, and the substring after the @ is the - domain name. - """ - names = remote_user.rsplit('@', 1) - username = names.pop(0) - if names: - domain_name = names[0] - domain_ref = self.resource_api.get_domain_by_name(domain_name) - domain_id = domain_ref['id'] - else: - domain_id = CONF.identity.default_domain_id - user_ref = self.identity_api.get_user_by_name(username, domain_id) - return user_ref diff --git a/keystone-moon/keystone/auth/plugins/mapped.py b/keystone-moon/keystone/auth/plugins/mapped.py index abf44481..220ff013 100644 --- a/keystone-moon/keystone/auth/plugins/mapped.py +++ b/keystone-moon/keystone/auth/plugins/mapped.py @@ -13,14 +13,13 @@ import functools from oslo_log import log -from oslo_serialization import jsonutils 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.contrib import federation +from keystone.contrib.federation import constants as federation_constants from keystone.contrib.federation import utils from keystone import exception from keystone.i18n import _ @@ -33,8 +32,8 @@ LOG = log.getLogger(__name__) METHOD_NAME = 'mapped' -@dependency.requires('assignment_api', 'federation_api', 'identity_api', - 'token_provider_api') +@dependency.requires('federation_api', 'identity_api', + 'resource_api', 'token_provider_api') class Mapped(auth.AuthMethodHandler): def _get_token_ref(self, auth_payload): @@ -44,7 +43,7 @@ class Mapped(auth.AuthMethodHandler): token_data=response) def authenticate(self, context, auth_payload, auth_context): - """Authenticate mapped user and return an authentication 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 @@ -66,7 +65,7 @@ class Mapped(auth.AuthMethodHandler): self.token_provider_api) else: handle_unscoped_token(context, auth_payload, auth_context, - self.assignment_api, self.federation_api, + self.resource_api, self.federation_api, self.identity_api) @@ -101,12 +100,12 @@ def handle_scoped_token(context, auth_payload, auth_context, token_ref, auth_context['user_id'] = user_id auth_context['group_ids'] = group_ids - auth_context[federation.IDENTITY_PROVIDER] = identity_provider - auth_context[federation.PROTOCOL] = protocol + auth_context[federation_constants.IDENTITY_PROVIDER] = identity_provider + auth_context[federation_constants.PROTOCOL] = protocol def handle_unscoped_token(context, auth_payload, auth_context, - assignment_api, federation_api, identity_api): + resource_api, federation_api, identity_api): def is_ephemeral_user(mapped_properties): return mapped_properties['user']['type'] == utils.UserType.EPHEMERAL @@ -115,8 +114,9 @@ def handle_unscoped_token(context, auth_payload, auth_context, identity_provider, protocol): auth_context['user_id'] = user['id'] auth_context['group_ids'] = mapped_properties['group_ids'] - auth_context[federation.IDENTITY_PROVIDER] = identity_provider - auth_context[federation.PROTOCOL] = protocol + 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, @@ -139,17 +139,15 @@ def handle_unscoped_token(context, auth_payload, auth_context, user_id = None try: - mapped_properties = apply_mapping_filter( - identity_provider, protocol, assertion, assignment_api, + mapped_properties, mapping_id = apply_mapping_filter( + identity_provider, protocol, assertion, resource_api, federation_api, identity_api) if is_ephemeral_user(mapped_properties): user = setup_username(context, mapped_properties) user_id = user['id'] group_ids = mapped_properties['group_ids'] - mapping = federation_api.get_mapping_from_idp_and_protocol( - identity_provider, protocol) - utils.validate_groups_cardinality(group_ids, mapping['id']) + utils.validate_groups_cardinality(group_ids, mapping_id) build_ephemeral_user_context(auth_context, user, mapped_properties, identity_provider, protocol) @@ -182,32 +180,29 @@ def extract_assertion_data(context): def apply_mapping_filter(identity_provider, protocol, assertion, - assignment_api, federation_api, identity_api): + resource_api, federation_api, identity_api): idp = federation_api.get_idp(identity_provider) - utils.validate_idp(idp, assertion) - mapping = federation_api.get_mapping_from_idp_and_protocol( - identity_provider, protocol) - rules = jsonutils.loads(mapping['rules']) - LOG.debug('using the following rules: %s', rules) - rule_processor = utils.RuleProcessor(rules) - mapped_properties = rule_processor.process(assertion) + 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 assignment_api + # ``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'], + mapping_id, identity_api) group_ids.extend( utils.transform_to_group_ids( - mapped_properties['group_names'], mapping['id'], - identity_api, assignment_api)) + mapped_properties['group_names'], mapping_id, + identity_api, resource_api)) mapped_properties['group_ids'] = list(set(group_ids)) - return mapped_properties + return mapped_properties, mapping_id def setup_username(context, mapped_properties): @@ -241,12 +236,17 @@ def setup_username(context, mapped_properties): user_name = user.get('name') or context['environment'].get('REMOTE_USER') if not any([user_id, user_name]): - raise exception.Unauthorized(_("Could not map user")) + 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'] = parse.quote(user_name) + user_id = user_name + + user['id'] = parse.quote(user_id) return user diff --git a/keystone-moon/keystone/auth/plugins/oauth1.py b/keystone-moon/keystone/auth/plugins/oauth1.py index 2f1cc2fa..e081cd62 100644 --- a/keystone-moon/keystone/auth/plugins/oauth1.py +++ b/keystone-moon/keystone/auth/plugins/oauth1.py @@ -29,15 +29,9 @@ LOG = log.getLogger(__name__) @dependency.requires('oauth_api') class OAuth(auth.AuthMethodHandler): - - method = 'oauth1' - def authenticate(self, context, auth_info, auth_context): """Turn a signed request with an access key into a keystone token.""" - if not self.oauth_api: - raise exception.Unauthorized(_('%s not supported') % self.method) - headers = context['headers'] oauth_headers = oauth.get_oauth_headers(headers) access_token_id = oauth_headers.get('oauth_token') diff --git a/keystone-moon/keystone/auth/plugins/password.py b/keystone-moon/keystone/auth/plugins/password.py index c5770445..16492a32 100644 --- a/keystone-moon/keystone/auth/plugins/password.py +++ b/keystone-moon/keystone/auth/plugins/password.py @@ -20,6 +20,7 @@ from keystone.common import dependency from keystone import exception from keystone.i18n import _ + METHOD_NAME = 'password' LOG = log.getLogger(__name__) @@ -28,11 +29,9 @@ LOG = log.getLogger(__name__) @dependency.requires('identity_api') class Password(auth.AuthMethodHandler): - method = METHOD_NAME - def authenticate(self, context, auth_payload, auth_context): """Try to authenticate against the identity backend.""" - user_info = auth_plugins.UserAuthInfo.create(auth_payload, self.method) + user_info = auth_plugins.UserAuthInfo.create(auth_payload, METHOD_NAME) # FIXME(gyee): identity.authenticate() can use some refactoring since # all we care is password matches diff --git a/keystone-moon/keystone/auth/plugins/saml2.py b/keystone-moon/keystone/auth/plugins/saml2.py index 744f26a9..cf7a8a50 100644 --- a/keystone-moon/keystone/auth/plugins/saml2.py +++ b/keystone-moon/keystone/auth/plugins/saml2.py @@ -23,5 +23,4 @@ This plugin subclasses mapped.Mapped, and may be specified in keystone.conf: class Saml2(mapped.Mapped): - - method = 'saml2' + pass diff --git a/keystone-moon/keystone/auth/plugins/token.py b/keystone-moon/keystone/auth/plugins/token.py index 5ca0b257..069f1140 100644 --- a/keystone-moon/keystone/auth/plugins/token.py +++ b/keystone-moon/keystone/auth/plugins/token.py @@ -33,8 +33,6 @@ CONF = cfg.CONF @dependency.requires('federation_api', 'identity_api', 'token_provider_api') class Token(auth.AuthMethodHandler): - method = 'token' - def _get_token_ref(self, auth_payload): token_id = auth_payload['id'] response = self.token_provider_api.validate_token(token_id) @@ -44,7 +42,7 @@ class Token(auth.AuthMethodHandler): def authenticate(self, context, auth_payload, user_context): if 'id' not in auth_payload: raise exception.ValidationError(attribute='id', - target=self.method) + target='token') token_ref = self._get_token_ref(auth_payload) if token_ref.is_federated_user and self.federation_api: mapped.handle_scoped_token( -- cgit 1.2.3-korg