Projet

Général

Profil

0001-ldap-to-database-users-synchronization-command.patch

Serghei Mihai (congés, retour 15/05), 06 janvier 2015 14:34

Télécharger (11,1 ko)

Voir les différences:

Subject: [PATCH] ldap to database users synchronization command.

Some of ldap backend's methods refactored

Closes #6183
 authentic2/backends/ldap_backend.py               | 62 +++++++++++------------
 authentic2/management/commands/sync-ldap-users.py | 34 +++++++++++++
 2 files changed, 65 insertions(+), 31 deletions(-)
 create mode 100644 authentic2/management/commands/sync-ldap-users.py
authentic2/backends/ldap_backend.py
79 79
    # realm for selecting an ldap configuration or formatting usernames
80 80
    'realm': 'ldap',
81 81
    # template for building username
82
    'username_template': '{username}@{realm}',
82
    'username_template': '{uid}@{realm}',
83 83
    # allow to match multiple user records
84 84
    'multimatch': True,
85 85
    # update username on all login, use with CAUTION !! only if you know that
......
430 430
                    log.error('user bind failed: authz_id not found %r', ', '.join(authz_ids))
431 431
                    if block['replicas']:
432 432
                        break
433
                return self._return_user(uri, authz_id, username, password, conn, block)
433
                return self._return_user(uri, authz_id, password, conn, block)
434 434
            except ldap.SERVER_DOWN:
435 435
                log.error('ldap authentication error: %r is down', uri)
436 436
            finally:
......
456 456
    def backend_name(self):
457 457
        return '%s.%s' % (__name__, self.__class__.__name__)
458 458

  
459
    def create_username(self, uri, dn, username, password, conn, block, attributes):
459
    def create_username(self, uri, dn, conn, block, attributes):
460 460
        '''Build a username using the configured template'''
461 461
        username_template = unicode(block['username_template'])
462
        return username_template.format(username=username, uri=uri,
462
        # create the uid from user's dn
463
        uid = dn.split(',')[0]
464
        uid = uid.split('=')[1]
465
        return username_template.format(uid=uid, uri=uri,
463 466
                block=block, realm=block['realm'], **attributes)
464 467

  
465 468
    def save_user(self, user, username):
......
480 483
                transaction.savepoint_rollback(sid)
481 484
            username = u'{0}{1}@{2}'.format(left, i, right)
482 485

  
483
    def populate_user_attributes(self, user, uri, dn, conn, block, attributes):
484
        for legacy_attribute, legacy_field in (('email', 'email_field'), 
486
    def populate_user_attributes(self, user, block, attributes):
487
        for legacy_attribute, legacy_field in (('email', 'email_field'),
485 488
                ('first_name', 'fname_field'), ('last_name', 'lname_field')):
486 489
            ldap_attribute = block[legacy_field]
487 490
            if not ldap_attribute:
......
511 514
            return True
512 515
        return False
513 516

  
514
    def populate_admin_flags_by_group(self, user, uri, dn, conn, block, group_dns):
517
    def populate_admin_flags_by_group(self, user, block, group_dns):
515 518
        '''Attribute admin flags based on groups.
516 519

  
517 520
           It supersedes is_staff, is_superuser and is_active.'''
......
526 529
            else:
527 530
                setattr(user, attr, False)
528 531

  
529
    def populate_groups_by_mapping(self, user, uri, dn, conn, block, group_dns):
532
    def populate_groups_by_mapping(self, user, dn, conn, block, group_dns):
530 533
        '''Assign group to user based on a mapping from group DNs'''
531 534
        group_mapping = block['group_mapping']
532 535
        if not group_mapping:
......
541 544
                    except KeyError:
542 545
                        pass
543 546

  
544
    def get_ldap_group_dns(self, user, uri, dn, conn, block):
547
    def get_ldap_group_dns(self, user, dn, conn, block):
545 548
        '''Retrieve group DNs from the LDAP by attributes (memberOf) or by
546 549
           filter.
547 550
        '''
......
565 568
                group_dns.update(dn for dn, attributes in results)
566 569
        return group_dns
567 570

  
568
    def populate_user_groups(self, user, uri, dn, conn, block):
569
        group_dns = self.get_ldap_group_dns(user, uri, dn, conn, block)
571
    def populate_user_groups(self, user, dn, conn, block):
572
        group_dns = self.get_ldap_group_dns(user, dn, conn, block)
570 573
        log.debug('groups for dn %r: %r', dn, group_dns)
571
        self.populate_admin_flags_by_group(user, uri, dn, conn, block, group_dns)
572
        self.populate_groups_by_mapping(user, uri, dn, conn, block, group_dns)
574
        self.populate_admin_flags_by_group(user, block, group_dns)
575
        self.populate_groups_by_mapping(user, dn, conn, block, group_dns)
573 576

  
574 577

  
575 578
    def get_group_by_name(self, block, group_name, create=None):
......
585 588
            except Group.DoesNotExist:
586 589
                return None
587 590

  
588
    def populate_mandatory_groups(self, user, uri, dn, conn, block):
591
    def populate_mandatory_groups(self, user, block):
589 592
        mandatory_groups = block.get('set_mandatory_groups')
590 593
        if not mandatory_groups:
591 594
            return
......
594 597
            if group:
595 598
                user.groups.add(group)
596 599

  
597
    def populate_admin_fields(self, user, uri, dn, conn, block):
600
    def populate_admin_fields(self, user, block):
598 601
        if block['is_staff'] is not None:
599 602
            user.is_staff = block['is_staff']
600 603
        if block['is_superuser'] is not None:
601 604
            user.is_superuser = block['is_superuser']
602 605

  
603
    def populate_user(self, user, uri, dn, username, conn, block, attributes):
604
        self.update_user_identifiers(user, uri, dn, username, conn, block,
605
                attributes)
606
        self.populate_user_attributes(user, uri, dn, conn, block, attributes)
607
        self.populate_admin_fields(user, uri, dn, conn, block)
608
        self.populate_mandatory_groups(user, uri, dn, conn, block)
609
        self.populate_user_groups(user, uri, dn, conn, block)
606
    def populate_user(self, user, dn, username, conn, block, attributes):
607
        self.update_user_identifiers(user, username, block, attributes)
608
        self.populate_user_attributes(user, block, attributes)
609
        self.populate_admin_fields(user, block)
610
        self.populate_mandatory_groups(user, block)
611
        self.populate_user_groups(user, dn, conn, block)
610 612

  
611 613
    @classmethod
612 614
    def attribute_name_from_external_id_tuple(cls, external_id_tuple):
......
723 725
            except User.DoesNotExist:
724 726
                pass
725 727

  
726
    def lookup_existing_user(self, uri, dn, username, password, conn, block, attributes):
728
    def lookup_existing_user(self, username, block, attributes):
727 729
        for lookup_type in block['lookups']:
728 730
            if lookup_type == 'username':
729 731
                return self.lookup_by_username(username)
730 732
            elif lookup_type == 'external_id':
731 733
                return self.lookup_by_external_id(block, attributes)
732 734

  
733
    def update_user_identifiers(self, user, uri, dn, username, conn,
734
            block, attributes):
735
    def update_user_identifiers(self, user, username, block, attributes):
735 736
        if block['transient']:
736 737
            return
737 738
        # if username has changed and we propagate those changes, update it
......
762 763
                        .delete()
763 764

  
764 765
    @commit_on_success
765
    def _return_user(self, uri, dn, username, password, conn, block):
766
    def _return_user(self, uri, dn, password, conn, block):
766 767
        attributes = self.get_ldap_attributes(block, conn, dn)
767 768
        if attributes is None:
768 769
            # attributes retrieval failed
769 770
            return
770 771
        log.debug('retrieved attributes for %r: %r', dn, attributes)
771
        username = self.create_username(uri, dn, username, password, conn,
772
                block, attributes)
772
        username = self.create_username(uri, dn, conn, block, attributes)
773 773
        if block['transient']:
774 774
            return self._return_transient_user(uri, dn, username, password,
775 775
                    conn, block, attributes)
......
780 780
    def _return_transient_user(self, uri, dn, username, password, conn, block, attributes):
781 781
        user = LDAPUser(username=username)
782 782
        user.ldap_init(block, dn, password, transient=True)
783
        self.populate_user(user, uri, dn, username, conn, block, attributes)
783
        self.populate_user(user, dn, username, conn, block, attributes)
784 784
        user.pk = 'transient!{0}'.format(base64.b64encode(pickle.dumps(user)))
785 785
        return user
786 786

  
787 787
    def _return_django_user(self, uri, dn, username, password, conn, block, attributes):
788
        user = self.lookup_existing_user(uri, dn, username, password, conn, block, attributes)
788
        user = self.lookup_existing_user(username, block, attributes)
789 789
        if user:
790 790
            created = False
791 791
            log.debug('found existing user %r', user)
......
793 793
            created = True
794 794
            user = LDAPUser()
795 795
        user.ldap_init(block, dn, password)
796
        self.populate_user(user, uri, dn, username, conn, block, attributes)
796
        self.populate_user(user, dn, username, conn, block, attributes)
797 797
        if block['keep_password']:
798 798
            if created:
799 799
                user.set_password(password)
authentic2/management/commands/sync-ldap-users.py
1
try:
2
    import ldap
3
    from ldap.filter import filter_format
4
except ImportError:
5
    ldap = None
6

  
7
from django.core.management.base import BaseCommand, CommandError
8

  
9
from authentic2.backends.ldap_backend import LDAPBackend, LDAPUser, \
10
    get_connection
11

  
12
class Command(BaseCommand):
13

  
14
    def handle(self, *args, **kwargs):
15
        backend = LDAPBackend()
16
        config = backend.get_config()
17
        for block in config:
18
            conn = get_connection(block)
19
            user_basedn = block.get('user_basedn', block['basedn'])
20
            user_filter = block['user_filter'].replace('%s', '*')
21
            attrs = block['attributes']
22
            users = conn.search_s(user_basedn, ldap.SCOPE_SUBTREE, user_filter, attrs)
23
            for user_dn, data in users:
24
                attrs = backend.get_ldap_attributes(block, conn, user_dn)
25
                username = backend.create_username(block['url'], user_dn,
26
                                                   conn, block, attrs)
27
                user = backend.lookup_existing_user(username, block, attrs)
28
                if not user:
29
                    user = LDAPUser(username=username)
30
                user.transient = False
31
                backend.populate_user(user, user_dn, username, conn, block, attrs)
32
                for name, value in user.attributes.iteritems():
33
                    setattr(user, name, value)
34
                user.save()
0
-