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 |
|
-
|