26 |
26 |
from hobo.agent.common.models import Role
|
27 |
27 |
from hobo.multitenant.utils import provision_user_groups
|
28 |
28 |
|
|
29 |
logger = logging.getLogger(__name__)
|
|
30 |
|
29 |
31 |
|
30 |
32 |
class TryAgain(Exception):
|
31 |
33 |
pass
|
32 |
34 |
|
33 |
35 |
|
|
36 |
def user_str(user):
|
|
37 |
'''Compute a string representation of user'''
|
|
38 |
s = ''
|
|
39 |
if user.first_name or user.last_name:
|
|
40 |
s += '"'
|
|
41 |
if user.first_name:
|
|
42 |
s += user.first_name
|
|
43 |
if user.first_name and user.last_name:
|
|
44 |
s += ' '
|
|
45 |
if user.last_name:
|
|
46 |
s += user.last_name
|
|
47 |
s += '" '
|
|
48 |
if user.email:
|
|
49 |
s += user.email + ' '
|
|
50 |
s += user.username
|
|
51 |
return s
|
|
52 |
|
|
53 |
|
34 |
54 |
class NotificationProcessing:
|
35 |
55 |
@classmethod
|
36 |
56 |
def check_valid_notification(cls, notification):
|
... | ... | |
72 |
92 |
try:
|
73 |
93 |
with atomic():
|
74 |
94 |
if action == 'provision':
|
|
95 |
new = False
|
|
96 |
updated = set()
|
|
97 |
attributes = {
|
|
98 |
'first_name': o['first_name'][:30],
|
|
99 |
'last_name': o['last_name'][:150],
|
|
100 |
'email': o['email'][:254],
|
|
101 |
'username': o['uuid'][:150],
|
|
102 |
'is_superuser': o['is_superuser'],
|
|
103 |
'is_staff': o['is_superuser'],
|
|
104 |
'is_active': o.get('is_active', True),
|
|
105 |
}
|
75 |
106 |
assert cls.check_valid_user(o)
|
76 |
107 |
try:
|
77 |
108 |
mellon_user = UserSAMLIdentifier.objects.get(issuer=issuer, name_id=o['uuid'])
|
... | ... | |
83 |
114 |
)
|
84 |
115 |
except User.DoesNotExist:
|
85 |
116 |
# temp user object
|
86 |
|
random_uid = str(random.randint(1, 10000000000000))
|
87 |
|
user = User.objects.create(username=random_uid)
|
|
117 |
user = User.objects.create(**attributes)
|
|
118 |
new = True
|
88 |
119 |
mellon_user = UserSAMLIdentifier.objects.create(
|
89 |
120 |
user=user, issuer=issuer, name_id=o['uuid']
|
90 |
121 |
)
|
91 |
|
user.first_name = o['first_name'][:30]
|
92 |
|
user.last_name = o['last_name'][:150]
|
93 |
|
user.email = o['email'][:254]
|
94 |
|
user.username = o['uuid'][:150]
|
95 |
|
user.is_superuser = o['is_superuser']
|
96 |
|
user.is_staff = o['is_superuser']
|
97 |
|
user.is_active = o.get('is_active', True)
|
98 |
|
user.save()
|
|
122 |
if not new:
|
|
123 |
for key in attributes:
|
|
124 |
if getattr(user, key) != attributes[key]:
|
|
125 |
setattr(user, key, attributes[key])
|
|
126 |
updated.add(key)
|
|
127 |
if updated:
|
|
128 |
user.save()
|
|
129 |
if new:
|
|
130 |
logger.info('provisionned new user %s', user_str(user))
|
|
131 |
if updated:
|
|
132 |
logger.info('updated user %s(%s)', user_str(user), updated)
|
99 |
133 |
role_uuids = [role['uuid'] for role in o.get('roles', [])]
|
100 |
134 |
provision_user_groups(user, role_uuids)
|
101 |
135 |
elif action == 'deprovision':
|
... | ... | |
104 |
138 |
except IntegrityError:
|
105 |
139 |
raise TryAgain
|
106 |
140 |
if full and action == 'provision':
|
107 |
|
for usi in UserSAMLIdentifier.objects.exclude(name_id__in=uuids):
|
|
141 |
qs = UserSAMLIdentifier.objects.exclude(name_id__in=uuids)
|
|
142 |
for user in qs:
|
|
143 |
logger.info('deprovisionning user %s', user_str(user))
|
|
144 |
for usi in qs:
|
108 |
145 |
usi.user.delete()
|
109 |
146 |
elif action == 'deprovision':
|
110 |
|
for user in User.objects.filter(saml_identifiers__name_id__in=uuids):
|
|
147 |
qs = User.objects.filter(saml_identifiers__name_id__in=uuids)
|
|
148 |
for user in qs:
|
|
149 |
logger.info('deprovisionning user %s', user_str(user))
|
|
150 |
for user in qs:
|
111 |
151 |
user.delete()
|
112 |
152 |
|
113 |
153 |
group_name_max_length = Group._meta.get_field('name').max_length
|
... | ... | |
125 |
165 |
|
126 |
166 |
@classmethod
|
127 |
167 |
def provision_role(cls, issuer, action, data, full=False):
|
128 |
|
logger = logging.getLogger(__name__)
|
129 |
168 |
uuids = set()
|
130 |
169 |
for o in data:
|
131 |
170 |
assert 'uuid' in o
|
132 |
171 |
uuids.add(o['uuid'])
|
133 |
172 |
if action == 'provision':
|
|
173 |
created = False
|
|
174 |
save = False
|
134 |
175 |
assert cls.check_valid_role(o)
|
135 |
176 |
role_name = cls.truncate_role_name(o['name'])
|
136 |
177 |
try:
|
137 |
178 |
role = Role.objects.get(uuid=o['uuid'])
|
138 |
|
created = False
|
139 |
179 |
except Role.DoesNotExist:
|
140 |
180 |
try:
|
141 |
181 |
with atomic():
|
... | ... | |
144 |
184 |
defaults={
|
145 |
185 |
'uuid': o['uuid'],
|
146 |
186 |
'description': o['description'],
|
147 |
|
'details': o.get('details', u''),
|
|
187 |
'details': o.get('details', ''),
|
148 |
188 |
'emails': o.get('emails', []),
|
149 |
189 |
'emails_to_members': o.get('emails_to_members', True),
|
150 |
190 |
},
|
151 |
191 |
)
|
152 |
192 |
except IntegrityError:
|
153 |
193 |
# Can happen if uuid and name already exist
|
154 |
|
logger.error(u'cannot provision role "%s" (%s)', o['name'], o['uuid'])
|
|
194 |
logger.error('cannot provision role "%s" (%s)', o['name'], o['uuid'])
|
155 |
195 |
continue
|
156 |
196 |
if not created:
|
157 |
|
save = False
|
158 |
197 |
if role.name != role_name:
|
159 |
198 |
role.name = role_name
|
160 |
199 |
save = True
|
... | ... | |
164 |
203 |
if role.description != o['description']:
|
165 |
204 |
role.description = o['description']
|
166 |
205 |
save = True
|
167 |
|
if role.details != o.get('details', u''):
|
168 |
|
role.details = o.get('details', u'')
|
|
206 |
if role.details != o.get('details', ''):
|
|
207 |
role.details = o.get('details', '')
|
169 |
208 |
save = True
|
170 |
209 |
if role.emails != o.get('emails', []):
|
171 |
210 |
role.emails = o.get('emails', [])
|
... | ... | |
179 |
218 |
role.save()
|
180 |
219 |
except IntegrityError:
|
181 |
220 |
# Can happen if uuid and name already exist
|
182 |
|
logger.error(u'cannot provision role "%s" (%s)', o['name'], o['uuid'])
|
|
221 |
logger.error('cannot provision role "%s" (%s)', o['name'], o['uuid'])
|
183 |
222 |
continue
|
|
223 |
if created:
|
|
224 |
logger.info('provisionned new role %s (%s)', o['name'], o['uuid'])
|
|
225 |
if save:
|
|
226 |
logger.info('updated role %s (%s)', o['name'], o['uuid'])
|
184 |
227 |
if full and action == 'provision':
|
185 |
|
for role in Role.objects.exclude(uuid__in=uuids):
|
|
228 |
qs = Role.objects.exclude(uuid__in=uuids)
|
|
229 |
logger.info(
|
|
230 |
'deprovisionning roles %s',
|
|
231 |
', '.join('%s (%s)' % (name, uuid) for name, uuid in qs.values_list('name', 'uuid')),
|
|
232 |
)
|
|
233 |
for role in qs:
|
186 |
234 |
role.delete()
|
187 |
235 |
elif action == 'deprovision':
|
188 |
|
for role in Role.objects.filter(uuid__in=uuids):
|
|
236 |
qs = Role.objects.filter(uuid__in=uuids)
|
|
237 |
logger.info(
|
|
238 |
'deprovisionning roles %s',
|
|
239 |
', '.join('%s (%s)' % (name, uuid) for name, uuid in qs.values_list('name', 'uuid')),
|
|
240 |
)
|
|
241 |
for role in qs:
|
189 |
242 |
role.delete()
|
190 |
243 |
|
191 |
244 |
@classmethod
|
192 |
|
-
|