13 |
13 |
import urllib
|
14 |
14 |
import six
|
15 |
15 |
import os
|
|
16 |
import json
|
16 |
17 |
|
17 |
18 |
# code originaly copied from by now merely inspired by
|
18 |
19 |
# http://www.amherst.k12.oh.us/django-ldap.html
|
... | ... | |
253 |
254 |
'mandatory_attributes_values': {},
|
254 |
255 |
# mapping from LDAP attributes name to other names
|
255 |
256 |
'attribute_mappings': [],
|
|
257 |
# extra attributes retrieve by making other LDAP search using user object informations
|
|
258 |
'extra_attributes': {},
|
256 |
259 |
# realm for selecting an ldap configuration or formatting usernames
|
257 |
260 |
'realm': 'ldap',
|
258 |
261 |
# template for building username
|
... | ... | |
683 |
686 |
external_id_tuple))
|
684 |
687 |
for from_at, to_at in block['attribute_mappings']:
|
685 |
688 |
attributes.add(to_at)
|
|
689 |
for extra_at in block.get('extra_attributes', {}):
|
|
690 |
if 'loop_over_attribute' in block['extra_attributes'][extra_at]:
|
|
691 |
attributes.add(block['extra_attributes'][extra_at]['loop_over_attribute'])
|
|
692 |
at_mapping = block['extra_attributes'][extra_at].get('mapping',{})
|
|
693 |
for key in at_mapping:
|
|
694 |
if at_mapping[key] != 'dn':
|
|
695 |
attributes.add(at_mapping[key])
|
686 |
696 |
return list(set(map(str.lower, map(str, attributes))))
|
687 |
697 |
|
688 |
698 |
@classmethod
|
... | ... | |
713 |
723 |
old = attribute_map.setdefault(to_attribute, [])
|
714 |
724 |
new = set(old) | set(attribute_map[from_attribute])
|
715 |
725 |
attribute_map[to_attribute] = list(new)
|
|
726 |
|
716 |
727 |
attribute_map['dn'] = dn
|
|
728 |
|
|
729 |
# extra attributes
|
|
730 |
attribute_map = cls.get_ldap_extra_attributes(block, conn, dn, attribute_map)
|
|
731 |
|
|
732 |
return attribute_map
|
|
733 |
|
|
734 |
@classmethod
|
|
735 |
def get_ldap_extra_attributes(cls, block, conn, dn, attribute_map):
|
|
736 |
'''Retrieve extra attributes from LDAP'''
|
|
737 |
|
|
738 |
ldap_scopes = {
|
|
739 |
'base': ldap.SCOPE_BASE,
|
|
740 |
'one': ldap.SCOPE_ONELEVEL,
|
|
741 |
'sub': ldap.SCOPE_SUBTREE,
|
|
742 |
}
|
|
743 |
for extra_attribute_name in block.get('extra_attributes', {}):
|
|
744 |
extra_attribute_config = block['extra_attributes'][extra_attribute_name]
|
|
745 |
extra_attribute_values = []
|
|
746 |
if 'loop_over_attribute' in extra_attribute_config:
|
|
747 |
extra_attribute_config['loop_over_attribute']=str.lower(extra_attribute_config['loop_over_attribute'])
|
|
748 |
if extra_attribute_config['loop_over_attribute'] not in attribute_map:
|
|
749 |
log.debug('loop_over_attribute %s not present (or empty) in user object attributes retreived. Pass.' % extra_attribute_config['loop_over_attribute'])
|
|
750 |
continue
|
|
751 |
if 'filter' not in extra_attribute_config and 'basedn' not in extra_attribute_config:
|
|
752 |
log.warning('Extra attribute %s not correctly configured : you need to defined at least one of filter or basedn parameters' % extra_attribute_name)
|
|
753 |
for item in attribute_map[extra_attribute_config['loop_over_attribute']]:
|
|
754 |
ldap_filter = unicode(extra_attribute_config.get('filter','objectClass=*')).format(item=item, **attribute_map)
|
|
755 |
ldap_basedn = unicode(extra_attribute_config.get('basedn',block.get('basedn'))).format(item=item, **attribute_map)
|
|
756 |
ldap_scope = ldap_scopes.get(extra_attribute_config.get('scope','sub'), ldap.SCOPE_SUBTREE)
|
|
757 |
ldap_attributes_mapping = extra_attribute_config.get('mapping', {})
|
|
758 |
ldap_attributes_names = filter(lambda a: a != 'dn', ldap_attributes_mapping.values())
|
|
759 |
try:
|
|
760 |
results = conn.search_s(ldap_basedn, ldap_scope, ldap_filter, ldap_attributes_names)
|
|
761 |
except ldap.LDAPError:
|
|
762 |
log.exception('unable to retrieve extra attribute %s for item %s' % (extra_attribute_name, item))
|
|
763 |
continue
|
|
764 |
item_value={}
|
|
765 |
for obj in results:
|
|
766 |
obj_attributes=cls.normalize_ldap_results(obj[1])
|
|
767 |
obj_attributes[dn]=obj[0]
|
|
768 |
for key in ldap_attributes_mapping:
|
|
769 |
item_value[key]=obj_attributes.get(ldap_attributes_mapping[key].lower())
|
|
770 |
if not item_value[key]:
|
|
771 |
del item_value[key]
|
|
772 |
elif len(item_value[key])==1:
|
|
773 |
item_value[key]=item_value[key][0]
|
|
774 |
extra_attribute_values.append(item_value)
|
|
775 |
else:
|
|
776 |
log.warning('loop_over_attribute not defined for extra attribute %s' % extra_attribute_name)
|
|
777 |
extra_attribute_serialization = extra_attribute_config.get('serialization',None)
|
|
778 |
if extra_attribute_serialization is None:
|
|
779 |
attribute_map[extra_attribute_name] = extra_attribute_values
|
|
780 |
elif extra_attribute_serialization == 'json':
|
|
781 |
attribute_map[extra_attribute_name] = json.dumps(extra_attribute_values)
|
|
782 |
else:
|
|
783 |
log.warning('Invalid serialization type "%s" for extra attribute %s' % (extra_attribute_serialization, extra_attribute_name))
|
|
784 |
|
717 |
785 |
return attribute_map
|
718 |
786 |
|
719 |
787 |
@classmethod
|
... | ... | |
852 |
920 |
for block in cls.get_config():
|
853 |
921 |
names.update(cls.get_ldap_attributes_names(block))
|
854 |
922 |
names.update(block['mandatory_attributes_values'].keys())
|
|
923 |
names.update(block.get('extra_attributes',{}).keys())
|
855 |
924 |
return [(a, '%s (LDAP)' % a) for a in sorted(names)]
|
856 |
925 |
|
857 |
926 |
@classmethod
|
858 |
|
-
|