Projet

Général

Profil

0001-ldap-update-block-saved-in-LDAP-users-objects-with-d.patch

Benjamin Dauvergne, 23 mars 2015 17:00

Télécharger (10,5 ko)

Voir les différences:

Subject: [PATCH] ldap: update block saved in LDAP users objects with default
 values (#6784)

If a session is older thant the last upgrade then it can happend that
user.block miss keys which are now mandatory and have a default value.
To be sure those keys exist we update the block with default value each
time it is used, i.e. in LDAPUser.get_connection().
 src/authentic2/backends/ldap_backend.py | 148 +++++++++++++++++---------------
 1 file changed, 78 insertions(+), 70 deletions(-)
src/authentic2/backends/ldap_backend.py
247 247
    def has_usable_password(self):
248 248
        return self.block['user_can_change_password']
249 249

  
250 250
    def get_connection(self):
251 251
        ldap_password = self.get_ldap_password()
252 252
        credentials = ()
253 253
        if ldap_password:
254 254
            credentials = (self.dn, ldap_password)
255
        # must be redone if session is older than current code update and new
256
        # options have been added to the setting dictionnary for LDAP
257
        # authentication
258
        update_default(self.block)
255 259
        return get_connection(self.block, credentials=credentials)
256 260

  
257 261
    def get_attributes(self):
258 262
        conn = self.get_connection()
259 263
        return LDAPBackend.get_ldap_attributes(self.block, conn, self.dn)
260 264

  
261 265
    def save(self, *args, **kwargs):
262 266
        if self.transient:
......
266 270
            self.pk = self.keep_pk
267 271
        super(LDAPUser, self).save(*args, **kwargs)
268 272
        if hasattr(self, 'keep_pk'):
269 273
            self.pk = pk
270 274

  
271 275
class LDAPBackendError(RuntimeError):
272 276
    pass
273 277

  
278
def update_default(block):
279
    '''Add missing key to block based on default values'''
280
    for key in block:
281
        if not key in _VALID_CONFIG_KEYS:
282
            raise ImproperlyConfigured(
283
                ('"{}" : invalid LDAP_AUTH_SETTINGS key, '
284
                +'available are {}').format(key, _VALID_CONFIG_KEYS))
285

  
286
    for r in _REQUIRED:
287
        if r not in block:
288
            raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: missing required configuration option %r' % r)
289

  
290
    for d in _DEFAULTS:
291
        if d not in block:
292
            block[d] = _DEFAULTS[d]
293
        else:
294
            if isinstance(_DEFAULTS[d], six.string_types):
295
                if not isinstance(block[d], six.string_types):
296
                    raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: '
297
                            'attribute %r must be a string' % d)
298
                try:
299
                    block[d] = str(block[d])
300
                except UnicodeEncodeError:
301
                    raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: '
302
                            'attribute %r must be a string' % d)
303
            if isinstance(_DEFAULTS[d], bool) and not isinstance(block[d], bool):
304
                raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: '
305
                        'attribute %r must be a boolean' % d)
306
            if isinstance(_DEFAULTS[d], (list, tuple)) and not isinstance(block[d], (list, tuple)):
307
                raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: '
308
                        'attribute %r must be a list or a tuple' % d)
309
            if isinstance(_DEFAULTS[d], dict) and not isinstance(block[d], dict):
310
                raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: '
311
                        'attribute %r must be a dictionary' % d)
312
            if not isinstance(_DEFAULTS[d], bool) and d in _REQUIRED and not block[d]:
313
                raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: '
314
                        'attribute %r is required but is empty')
315
    for i in _TO_ITERABLE:
316
        if isinstance(block[i], six.string_types):
317
            block[i] = (block[i],)
318
    # lowercase LDAP attribute names
319
    block['external_id_tuples'] = map(lambda t: map(str.lower, map(str, t)), block['external_id_tuples'])
320
    block['attribute_mappings'] = map(lambda t: map(str.lower, map(str, t)), block['attribute_mappings'])
321
    for key in _TO_LOWERCASE:
322
        # we handle strings, list of strings and list of list or tuple whose first element is a string
323
        if isinstance(block[key], six.string_types):
324
            block[key] = str(block[key]).lower()
325
        elif isinstance(block[key], (list, tuple)):
326
            new_seq = []
327
            for elt in block[key]:
328
                if isinstance(elt, six.string_types):
329
                    elt = str(elt).lower()
330
                elif isinstance(elt, (list, tuple)):
331
                    elt = list(elt)
332
                    elt[0] = str(elt[0]).lower()
333
                    elt = tuple(elt)
334
                new_seq.append(elt)
335
            block[key] = tuple(new_seq)
336
        elif isinstance(block[key], dict):
337
            newdict = {}
338
            for subkey in block[key]:
339
                newdict[str(subkey).lower()] = block[key][subkey]
340
            block[key] = newdict
341
        else:
342
            raise NotImplementedError('LDAP setting %r cannot be '
343
                    'converted to lowercase '
344
                    'setting, its type is %r'
345
                    % (key, type(block[key])))
346
    # Want to randomize our access, otherwise what's the point of having multiple servers?
347
    block['url'] = list(block['url'])
348
    if block['shuffle_replicas']:
349
        random.shuffle(block['url'])
350

  
274 351
class LDAPBackend(object):
275 352
    @classmethod
276 353
    @to_list
277 354
    def get_realms(self):
278 355
        config = self.get_config()
279 356
        for block in config:
280 357
            yield block['realm']
281 358

  
......
284 361
        if not getattr(settings, 'LDAP_AUTH_SETTINGS', []):
285 362
            return []
286 363
        if isinstance(settings.LDAP_AUTH_SETTINGS[0], dict):
287 364
            blocks = settings.LDAP_AUTH_SETTINGS
288 365
        else:
289 366
            blocks = (self._parse_simple_config(),)
290 367
        # First get our configuration into a standard format
291 368
        for block in blocks:
292
            for key in block:
293
                if not key in _VALID_CONFIG_KEYS:
294
                    raise ImproperlyConfigured(
295
                        ('"{}" : invalid LDAP_AUTH_SETTINGS key, '
296
                        +'available are {}').format(key, _VALID_CONFIG_KEYS))
297

  
298
            for r in _REQUIRED:
299
                if r not in block:
300
                    raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: missing required configuration option %r' % r)
301

  
302
            for d in _DEFAULTS:
303
                if d not in block:
304
                    block[d] = _DEFAULTS[d]
305
                else:
306
                    if isinstance(_DEFAULTS[d], six.string_types):
307
                        if not isinstance(block[d], six.string_types):
308
                            raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: '
309
                                    'attribute %r must be a string' % d)
310
                        try:
311
                            block[d] = str(block[d])
312
                        except UnicodeEncodeError:
313
                            raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: '
314
                                    'attribute %r must be a string' % d)
315
                    if isinstance(_DEFAULTS[d], bool) and not isinstance(block[d], bool):
316
                        raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: '
317
                                'attribute %r must be a boolean' % d)
318
                    if isinstance(_DEFAULTS[d], (list, tuple)) and not isinstance(block[d], (list, tuple)):
319
                        raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: '
320
                                'attribute %r must be a list or a tuple' % d)
321
                    if isinstance(_DEFAULTS[d], dict) and not isinstance(block[d], dict):
322
                        raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: '
323
                                'attribute %r must be a dictionary' % d)
324
                    if not isinstance(_DEFAULTS[d], bool) and d in _REQUIRED and not block[d]:
325
                        raise ImproperlyConfigured('LDAP_AUTH_SETTINGS: '
326
                                'attribute %r is required but is empty')
327
            for i in _TO_ITERABLE:
328
                if isinstance(block[i], six.string_types):
329
                    block[i] = (block[i],)
330
            # lowercase LDAP attribute names
331
            block['external_id_tuples'] = map(lambda t: map(str.lower, map(str, t)), block['external_id_tuples'])
332
            block['attribute_mappings'] = map(lambda t: map(str.lower, map(str, t)), block['attribute_mappings'])
333
            for key in _TO_LOWERCASE:
334
                # we handle strings, list of strings and list of list or tuple whose first element is a string
335
                if isinstance(block[key], six.string_types):
336
                    block[key] = str(block[key]).lower()
337
                elif isinstance(block[key], (list, tuple)):
338
                    new_seq = []
339
                    for elt in block[key]:
340
                        if isinstance(elt, six.string_types):
341
                            elt = str(elt).lower()
342
                        elif isinstance(elt, (list, tuple)):
343
                            elt = list(elt)
344
                            elt[0] = str(elt[0]).lower()
345
                            elt = tuple(elt)
346
                        new_seq.append(elt)
347
                    block[key] = tuple(new_seq)
348
                elif isinstance(block[key], dict):
349
                    newdict = {}
350
                    for subkey in block[key]:
351
                        newdict[str(subkey).lower()] = block[key][subkey]
352
                    block[key] = newdict
353
                else:
354
                    raise NotImplementedError('LDAP setting %r cannot be '
355
                            'converted to lowercase '
356
                            'setting, its type is %r'
357
                            % (key, type(block[key])))
358
            # Want to randomize our access, otherwise what's the point of having multiple servers?
359
            block['url'] = list(block['url'])
360
            if block['shuffle_replicas']:
361
                random.shuffle(block['url'])
369
            update_default(block)
362 370
        log.debug('got config %r', blocks)
363 371
        return blocks
364 372

  
365 373
    def authenticate(self, username=None, password=None, realm=None):
366 374
        if username is None or password is None:
367 375
            return None
368 376

  
369 377
        config = self.get_config()
370
-