Project

General

Profile

0001-provisionning-factorize-user-creation-59135.patch

Benjamin Dauvergne, 30 June 2022 11:24 PM

Download (6.16 KB)

View differences:

Subject: [PATCH 1/3] provisionning: factorize user creation (#59135)

 hobo/provisionning/utils.py | 109 ++++++++++++++++++------------------
 1 file changed, 55 insertions(+), 54 deletions(-)
hobo/provisionning/utils.py
17 17
import hashlib
18 18
import logging
19 19

  
20
from django.contrib.auth import get_user_model
20 21
from django.contrib.auth.models import Group
21 22
from django.db import IntegrityError
22 23
from django.db.models.query import Q
23 24
from django.db.transaction import atomic
25
from mellon.models import Issuer
24 26

  
25 27
from hobo.agent.common.models import Role
26 28
from hobo.multitenant.utils import provision_user_groups
......
50 52
    return s
51 53

  
52 54

  
55
def get_issuer(entity_id):
56
    issuer, created = Issuer.objects.get_or_create(entity_id=entity_id)
57
    return issuer
58

  
59

  
60
def provision_user(entity_id, o, tries=0):
61
    updated = set()
62
    attributes = {
63
        'username': o['uuid'][:150],
64
        'first_name': o['first_name'][:30],
65
        'last_name': o['last_name'][:150],
66
        'email': o['email'][:254],
67
        'is_superuser': o['is_superuser'],
68
        'is_staff': o['is_superuser'],
69
        'is_active': o.get('is_active', True),
70
    }
71

  
72
    User = get_user_model()
73
    user = get_user_from_name_id(name_id=o['uuid'], entity_id=entity_id) or User()
74

  
75
    for key in attributes:
76
        if getattr(user, key) != attributes[key]:
77
            setattr(user, key, attributes[key])
78
            updated.add(key)
79

  
80
    if not user.id:  # user is new
81
        issuer = get_issuer(entity_id)
82
        try:
83
            with atomic(savepoint=False):
84
                user.save()
85
                user.saml_identifiers.create(issuer=issuer, name_id=o['uuid'])
86
            logger.info('provisionned new user %s', user_str(user))
87
        except IntegrityError:
88
            if tries > 0:
89
                raise
90
            return provision_user(user, o, tries=tries + 1)
91
    elif updated:
92
        user.save()
93
        logger.info('updated user %s(%s)', user_str(user), updated)
94
    return user
95

  
96

  
53 97
class NotificationProcessing:
54 98
    @classmethod
55 99
    def check_valid_notification(cls, notification):
......
80 124

  
81 125
    @classmethod
82 126
    def provision_user(cls, issuer, action, data, full=False):
83
        from django.contrib.auth import get_user_model
84
        from mellon.models import Issuer, UserSAMLIdentifier
127
        assert not full  # provisionning all users is dangerous, we prefer deprovision
85 128

  
86 129
        User = get_user_model()
87

  
88
        assert not full  # provisionning all users is dangerous, we prefer deprovision
89 130
        uuids = set()
131

  
90 132
        for o in data:
91
            try:
92
                with atomic():
93
                    if action == 'provision':
94
                        new = False
95
                        updated = set()
96
                        attributes = {
97
                            'first_name': o['first_name'][:30],
98
                            'last_name': o['last_name'][:150],
99
                            'email': o['email'][:254],
100
                            'username': o['uuid'][:150],
101
                            'is_superuser': o['is_superuser'],
102
                            'is_staff': o['is_superuser'],
103
                            'is_active': o.get('is_active', True),
104
                        }
105
                        assert cls.check_valid_user(o)
106
                        try:
107
                            mellon_user = UserSAMLIdentifier.objects.get(
108
                                issuer__entity_id=issuer, name_id=o['uuid']
109
                            )
110
                            user = mellon_user.user
111
                        except UserSAMLIdentifier.DoesNotExist:
112
                            try:
113
                                user = User.objects.get(
114
                                    Q(username=o['uuid'][:30]) | Q(username=o['uuid'][:150])
115
                                )
116
                            except User.DoesNotExist:
117
                                # temp user object
118
                                user = User.objects.create(**attributes)
119
                                new = True
120
                            saml_issuer, created = Issuer.objects.get_or_create(entity_id=issuer)
121
                            mellon_user = UserSAMLIdentifier.objects.create(
122
                                user=user, issuer=saml_issuer, name_id=o['uuid']
123
                            )
124
                        if new:
125
                            logger.info('provisionned new user %s', user_str(user))
126
                        else:
127
                            for key in attributes:
128
                                if getattr(user, key) != attributes[key]:
129
                                    setattr(user, key, attributes[key])
130
                                    updated.add(key)
131
                            if updated:
132
                                user.save()
133
                                logger.info('updated user %s(%s)', user_str(user), updated)
134
                        role_uuids = [role['uuid'] for role in o.get('roles', [])]
135
                        provision_user_groups(user, role_uuids)
136
                    elif action == 'deprovision':
137
                        assert 'uuid' in o
138
                uuids.add(o['uuid'])
139
            except IntegrityError:
140
                raise TryAgain
133
            if action == 'provision':
134
                assert cls.check_valid_user(o)
135
                user = provision_user(issuer, o)
136
                role_uuids = [role['uuid'] for role in o.get('roles', [])]
137
                provision_user_groups(user, role_uuids)
138
            elif action == 'deprovision':
139
                assert 'uuid' in o
140
            uuids.add(o['uuid'])
141

  
141 142
        if (full and action == 'provision') or (action == 'deprovision'):
142 143
            if action == 'deprovision':
143 144
                qs = User.objects.filter(saml_identifiers__name_id__in=uuids)
144
-