33 |
33 |
import random
|
34 |
34 |
import base64
|
35 |
35 |
import os
|
|
36 |
import json
|
36 |
37 |
|
37 |
38 |
# code originaly copied from by now merely inspired by
|
38 |
39 |
# http://www.amherst.k12.oh.us/django-ldap.html
|
... | ... | |
449 |
450 |
'mandatory_attributes_values': {},
|
450 |
451 |
# mapping from LDAP attributes name to other names
|
451 |
452 |
'attribute_mappings': [],
|
|
453 |
# extra attributes retrieve by making other LDAP search using user object informations
|
|
454 |
'extra_attributes': {},
|
452 |
455 |
# realm for selecting an ldap configuration or formatting usernames
|
453 |
456 |
'realm': 'ldap',
|
454 |
457 |
# template for building username
|
... | ... | |
957 |
960 |
from_ldap = mapping.get('from_ldap')
|
958 |
961 |
if from_ldap:
|
959 |
962 |
attributes.add(from_ldap)
|
|
963 |
for extra_at in block.get('extra_attributes', {}):
|
|
964 |
if 'loop_over_attribute' in block['extra_attributes'][extra_at]:
|
|
965 |
attributes.add(block['extra_attributes'][extra_at]['loop_over_attribute'])
|
|
966 |
at_mapping = block['extra_attributes'][extra_at].get('mapping', {})
|
|
967 |
for key in at_mapping:
|
|
968 |
if at_mapping[key] != 'dn':
|
|
969 |
attributes.add(at_mapping[key])
|
960 |
970 |
return list(set(attribute.lower() for attribute in attributes))
|
961 |
971 |
|
962 |
972 |
@classmethod
|
... | ... | |
988 |
998 |
new = set(old) | set(attribute_map[from_attribute])
|
989 |
999 |
attribute_map[to_attribute] = list(new)
|
990 |
1000 |
attribute_map['dn'] = force_text(dn)
|
|
1001 |
|
|
1002 |
# extra attributes
|
|
1003 |
attribute_map = cls.get_ldap_extra_attributes(block, conn, dn, attribute_map)
|
|
1004 |
|
|
1005 |
return attribute_map
|
|
1006 |
|
|
1007 |
@classmethod
|
|
1008 |
def get_ldap_extra_attributes(cls, block, conn, dn, attribute_map):
|
|
1009 |
'''Retrieve extra attributes from LDAP'''
|
|
1010 |
|
|
1011 |
ldap_scopes = {
|
|
1012 |
'base': ldap.SCOPE_BASE,
|
|
1013 |
'one': ldap.SCOPE_ONELEVEL,
|
|
1014 |
'sub': ldap.SCOPE_SUBTREE,
|
|
1015 |
}
|
|
1016 |
log.debug(u'Attrs before extra attributes : %s' % attribute_map)
|
|
1017 |
for extra_attribute_name in block.get('extra_attributes', {}):
|
|
1018 |
extra_attribute_config = block['extra_attributes'][extra_attribute_name]
|
|
1019 |
extra_attribute_values = []
|
|
1020 |
if 'loop_over_attribute' in extra_attribute_config:
|
|
1021 |
extra_attribute_config['loop_over_attribute'] = extra_attribute_config['loop_over_attribute'].lower()
|
|
1022 |
if extra_attribute_config['loop_over_attribute'] not in attribute_map:
|
|
1023 |
log.debug('loop_over_attribute %s not present (or empty) in user object attributes retreived. Pass.' % extra_attribute_config['loop_over_attribute'])
|
|
1024 |
continue
|
|
1025 |
if 'filter' not in extra_attribute_config and 'basedn' not in extra_attribute_config:
|
|
1026 |
log.warning('Extra attribute %s not correctly configured : you need to defined at least one of filter or basedn parameters' % extra_attribute_name)
|
|
1027 |
for item in attribute_map[extra_attribute_config['loop_over_attribute']]:
|
|
1028 |
ldap_filter = force_text(extra_attribute_config.get('filter', 'objectClass=*')).format(item=item, **attribute_map)
|
|
1029 |
ldap_basedn = force_text(extra_attribute_config.get('basedn', block.get('basedn'))).format(item=item, **attribute_map)
|
|
1030 |
ldap_scope = ldap_scopes.get(extra_attribute_config.get('scope', 'sub'), ldap.SCOPE_SUBTREE)
|
|
1031 |
ldap_attributes_mapping = extra_attribute_config.get('mapping', {})
|
|
1032 |
ldap_attributes_names = filter(lambda a: a != 'dn', ldap_attributes_mapping.values())
|
|
1033 |
try:
|
|
1034 |
results = conn.search_s(ldap_basedn, ldap_scope, ldap_filter, list(ldap_attributes_names))
|
|
1035 |
except ldap.LDAPError:
|
|
1036 |
log.exception('unable to retrieve extra attribute %s for item %s' % (extra_attribute_name, item))
|
|
1037 |
continue
|
|
1038 |
item_value = {}
|
|
1039 |
for obj in results:
|
|
1040 |
log.debug(u'Object retrieved for extra attr %s with item %s : %s' % (extra_attribute_name, item, obj))
|
|
1041 |
obj_attributes = cls.normalize_ldap_results(obj[1])
|
|
1042 |
obj_attributes[dn] = obj[0]
|
|
1043 |
log.debug(u'Object attributes normalized for extra attr %s with item %s : %s' % (extra_attribute_name, item, obj_attributes))
|
|
1044 |
for key in ldap_attributes_mapping:
|
|
1045 |
item_value[key] = obj_attributes.get(ldap_attributes_mapping[key].lower())
|
|
1046 |
log.debug(u'Object attribute %s value retrieved for extra attr %s with item %s : %s' % (ldap_attributes_mapping[key], extra_attribute_name, item, item_value[key]))
|
|
1047 |
if not item_value[key]:
|
|
1048 |
del item_value[key]
|
|
1049 |
elif len(item_value[key]) == 1:
|
|
1050 |
item_value[key] = item_value[key][0]
|
|
1051 |
extra_attribute_values.append(item_value)
|
|
1052 |
else:
|
|
1053 |
log.warning('loop_over_attribute not defined for extra attribute %s' % extra_attribute_name)
|
|
1054 |
extra_attribute_serialization = extra_attribute_config.get('serialization', None)
|
|
1055 |
if extra_attribute_serialization is None:
|
|
1056 |
attribute_map[extra_attribute_name] = extra_attribute_values
|
|
1057 |
elif extra_attribute_serialization == 'json':
|
|
1058 |
attribute_map[extra_attribute_name] = json.dumps(extra_attribute_values)
|
|
1059 |
else:
|
|
1060 |
log.warning('Invalid serialization type "%s" for extra attribute %s' % (extra_attribute_serialization, extra_attribute_name))
|
991 |
1061 |
return attribute_map
|
992 |
1062 |
|
993 |
1063 |
@classmethod
|
... | ... | |
1137 |
1207 |
for block in cls.get_config():
|
1138 |
1208 |
names.update(cls.get_ldap_attributes_names(block))
|
1139 |
1209 |
names.update(map_text(block['mandatory_attributes_values']).keys())
|
|
1210 |
names.update(map_text(block.get('extra_attributes', {})).keys())
|
1140 |
1211 |
return [(a, '%s (LDAP)' % a) for a in sorted(names)]
|
1141 |
1212 |
|
1142 |
1213 |
@classmethod
|