summaryrefslogtreecommitdiffstats
path: root/keystone
diff options
context:
space:
mode:
authorAllan Feid <allanfeid@gmail.com>2013-03-21 14:19:48 -0400
committerAllan <allanfeid@gmail.com>2013-04-14 21:52:42 -0400
commitf452c3d6b15123ca1b383f1d200f4cb406c81852 (patch)
treefe70b8e28792b14a55a3388bceaadcf3dea60fe8 /keystone
parentb4db547d0a681fbf7c8927a8c07c8bb3844582fb (diff)
downloadkeystone-f452c3d6b15123ca1b383f1d200f4cb406c81852.tar.gz
keystone-f452c3d6b15123ca1b383f1d200f4cb406c81852.tar.xz
keystone-f452c3d6b15123ca1b383f1d200f4cb406c81852.zip
Allow additional attribute mappings in ldap
This is needed as a work around for objectclasses that require additional attributes other than just what is supplied in user_id_attribute and user_name_attribute. Change-Id: Ie6cdd0534b8389f62f98fdca7d19bc0feb9c131f Fixes: bug #1158077
Diffstat (limited to 'keystone')
-rw-r--r--keystone/common/config.py11
-rw-r--r--keystone/common/ldap/core.py36
2 files changed, 45 insertions, 2 deletions
diff --git a/keystone/common/config.py b/keystone/common/config.py
index d7b6ff73..d3f6741c 100644
--- a/keystone/common/config.py
+++ b/keystone/common/config.py
@@ -314,6 +314,8 @@ def configure():
register_bool('user_allow_delete', group='ldap', default=True)
register_bool('user_enabled_emulation', group='ldap', default=False)
register_str('user_enabled_emulation_dn', group='ldap', default=None)
+ register_list(
+ 'user_additional_attribute_mapping', group='ldap', default=None)
register_str('tenant_tree_dn', group='ldap', default=None)
register_str('tenant_filter', group='ldap', default=None)
@@ -331,6 +333,8 @@ def configure():
register_bool('tenant_allow_delete', group='ldap', default=True)
register_bool('tenant_enabled_emulation', group='ldap', default=False)
register_str('tenant_enabled_emulation_dn', group='ldap', default=None)
+ register_list(
+ 'tenant_additional_attribute_mapping', group='ldap', default=None)
register_str('role_tree_dn', group='ldap', default=None)
register_str('role_filter', group='ldap', default=None)
@@ -343,6 +347,8 @@ def configure():
register_bool('role_allow_create', group='ldap', default=True)
register_bool('role_allow_update', group='ldap', default=True)
register_bool('role_allow_delete', group='ldap', default=True)
+ register_list(
+ 'role_additional_attribute_mapping', group='ldap', default=None)
register_str('group_tree_dn', group='ldap', default=None)
register_str('group_filter', group='ldap', default=None)
@@ -357,6 +363,8 @@ def configure():
register_bool('group_allow_create', group='ldap', default=True)
register_bool('group_allow_update', group='ldap', default=True)
register_bool('group_allow_delete', group='ldap', default=True)
+ register_list(
+ 'group_additional_attribute_mapping', group='ldap', default=None)
register_str('domain_tree_dn', group='ldap', default=None)
register_str('domain_filter', group='ldap', default=None)
@@ -372,6 +380,9 @@ def configure():
register_bool('domain_allow_delete', group='ldap', default=True)
register_bool('domain_enabled_emulation', group='ldap', default=False)
register_str('domain_enabled_emulation_dn', group='ldap', default=None)
+ register_list(
+ 'domain_additional_attribute_mapping', group='ldap', default=None)
+
register_str('tls_cacertfile', group='ldap', default=None)
register_str('tls_cacertdir', group='ldap', default=None)
register_bool('use_tls', group='ldap', default=False)
diff --git a/keystone/common/ldap/core.py b/keystone/common/ldap/core.py
index 80189b10..7113fbbb 100644
--- a/keystone/common/ldap/core.py
+++ b/keystone/common/ldap/core.py
@@ -104,6 +104,7 @@ class BaseLdap(object):
DEFAULT_ID_ATTR = 'cn'
DEFAULT_OBJECTCLASS = None
DEFAULT_FILTER = None
+ DEFAULT_EXTRA_ATTR_MAPPING = []
DUMB_MEMBER_DN = 'cn=dumb,dc=nonexistent'
NotFound = None
notfound_arg = None
@@ -140,6 +141,12 @@ class BaseLdap(object):
self.object_class = (getattr(conf.ldap, objclass)
or self.DEFAULT_OBJECTCLASS)
+ attr_mapping_opt = ('%s_additional_attribute_mapping' %
+ self.options_name)
+ attr_mapping = (getattr(conf.ldap, attr_mapping_opt)
+ or self.DEFAULT_EXTRA_ATTR_MAPPING)
+ self.extra_attr_mapping = self._parse_extra_attrs(attr_mapping)
+
filter = '%s_filter' % self.options_name
self.filter = getattr(conf.ldap, filter) or self.DEFAULT_FILTER
@@ -169,6 +176,25 @@ class BaseLdap(object):
else:
return self.NotFound(**{self.notfound_arg: object_id})
+ def _parse_extra_attrs(self, option_list):
+ mapping = {}
+ for item in option_list:
+ try:
+ ldap_attr, attr_map = item.split(':')
+ except Exception:
+ LOG.warn(_('Invalid additional attribute mapping: "%s". '
+ 'Format must be ' +
+ '<ldap_attribute>:<keystone_attribute>') % item)
+ continue
+ if attr_map not in self.attribute_mapping:
+ LOG.warn(_('Invalid additional attribute mapping: "%(item)s". '
+ 'Value "%(attr_map)s" must use one of %(keys)s.') %
+ {'item': item, 'attr_map': attr_map,
+ 'keys': ', '.join(self.attribute_mapping.keys())})
+ continue
+ mapping[ldap_attr] = attr_map
+ return mapping
+
def get_connection(self, user=None, password=None):
if self.LDAP_URL.startswith('fake://'):
conn = fakeldap.FakeLdap(self.LDAP_URL)
@@ -272,6 +298,11 @@ class BaseLdap(object):
if v is not None:
attr_type = self.attribute_mapping.get(k, k)
attrs.append((attr_type, [v]))
+ extra_attrs = [attr for attr, name
+ in self.extra_attr_mapping.iteritems()
+ if name == k]
+ for attr in extra_attrs:
+ attrs.append((attr, [v]))
if 'groupOfNames' in object_classes and self.use_dumb_member:
attrs.append(('member', [self.dumb_member]))
@@ -289,8 +320,9 @@ class BaseLdap(object):
'filter': (filter or self.filter or ''),
'object_class': self.object_class})
try:
- res = conn.search_s(self.tree_dn, self.LDAP_SCOPE, query,
- self.attribute_mapping.values())
+ attrs = list(set((self.attribute_mapping.values() +
+ self.extra_attr_mapping.keys())))
+ res = conn.search_s(self.tree_dn, self.LDAP_SCOPE, query, attrs)
except ldap.NO_SUCH_OBJECT:
return None
try: