0001-misc-apply-pyupgrade-55519.patch
merge-coverage.py | ||
---|---|---|
1 | 1 |
#!/usr/bin/python |
2 |
from __future__ import print_function |
|
3 | 2 | |
4 | 3 |
import logging |
5 | 4 |
import os |
... | ... | |
145 | 144 |
for pckg in packages: |
146 | 145 |
name = pckg.get('name') |
147 | 146 |
if not include_package(name): |
148 |
logging.debug('excluding package "{0}"'.format(name))
|
|
147 |
logging.debug(f'excluding package "{name}"')
|
|
149 | 148 |
packageroot.remove(pckg) |
150 | 149 |
else: |
151 | 150 |
included.append(pckg) |
... | ... | |
158 | 157 | |
159 | 158 |
# create simple regexp from given filter |
160 | 159 |
for i in range(len(packagefilters)): |
161 |
packagefilters[i] = '^' + packagefilters[i].replace('.', '\.').replace('*', '.*') + '$' |
|
160 |
packagefilters[i] = '^' + packagefilters[i].replace('.', r'\.').replace('*', '.*') + '$'
|
|
162 | 161 | |
163 | 162 | |
164 | 163 |
def include_package(name): |
... | ... | |
265 | 264 |
for xmlfile in xmlfiles: |
266 | 265 |
xml = ET.parse(xmlfile) |
267 | 266 |
filter_xml(xml) |
268 |
logging.debug('{1}/{2} filtering: {0}'.format(xmlfile, currfile, totalfiles))
|
|
267 |
logging.debug(f'{currfile}/{totalfiles} filtering: {xmlfile}')
|
|
269 | 268 |
xml.write(xmlfile + filtersuffix, encoding="UTF-8", xml_declaration=True) |
270 | 269 |
currfile += 1 |
271 | 270 |
else: |
... | ... | |
283 | 282 |
sys.exit(0) |
284 | 283 | |
285 | 284 |
currfile = 1 |
286 |
logging.debug('{2}/{3} merging: {0} & {1}'.format(xmlfiles[0], xmlfiles[1], currfile, totalfiles - 1))
|
|
285 |
logging.debug(f'{currfile}/{totalfiles - 1} merging: {xmlfiles[0]} & {xmlfiles[1]}')
|
|
287 | 286 |
merge_xml(xmlfiles[0], xmlfiles[1], finalxml) |
288 | 287 | |
289 | 288 |
currfile = 2 |
290 | 289 |
for i in range(totalfiles - 2): |
291 | 290 |
xmlfile = xmlfiles[i + 2] |
292 |
logging.debug('{2}/{3} merging: {0} & {1}'.format(finalxml, xmlfile, currfile, totalfiles - 1))
|
|
291 |
logging.debug(f'{currfile}/{totalfiles - 1} merging: {finalxml} & {xmlfile}')
|
|
293 | 292 |
merge_xml(finalxml, xmlfile, finalxml) |
294 | 293 |
currfile += 1 |
setup.py | ||
---|---|---|
79 | 79 |
tag exists, take 0.0- and add the length of the commit log. |
80 | 80 |
""" |
81 | 81 |
if os.path.exists('VERSION'): |
82 |
with open('VERSION', 'r') as v:
|
|
82 |
with open('VERSION') as v: |
|
83 | 83 |
return v.read() |
84 | 84 |
if os.path.exists('.git'): |
85 | 85 |
p = subprocess.Popen( |
src/authentic2/a2_rbac/admin.py | ||
---|---|---|
26 | 26 |
fields = ['parent'] |
27 | 27 | |
28 | 28 |
def get_queryset(self, request): |
29 |
return super(RoleParentInline, self).get_queryset(request).filter(direct=True)
|
|
29 |
return super().get_queryset(request).filter(direct=True) |
|
30 | 30 | |
31 | 31 | |
32 | 32 |
class RoleChildInline(admin.TabularInline): |
... | ... | |
35 | 35 |
fields = ['child'] |
36 | 36 | |
37 | 37 |
def get_queryset(self, request): |
38 |
return super(RoleChildInline, self).get_queryset(request).filter(direct=True)
|
|
38 |
return super().get_queryset(request).filter(direct=True) |
|
39 | 39 | |
40 | 40 | |
41 | 41 |
class RoleAttributeInline(admin.TabularInline): |
src/authentic2/a2_rbac/app_settings.py | ||
---|---|---|
17 | 17 |
import sys |
18 | 18 | |
19 | 19 | |
20 |
class AppSettings(object):
|
|
20 |
class AppSettings: |
|
21 | 21 |
__DEFAULTS = dict( |
22 | 22 |
MANAGED_CONTENT_TYPES=None, |
23 | 23 |
ROLE_ADMIN_RESTRICT_TO_OU_USERS=False, |
src/authentic2/a2_rbac/fields.py | ||
---|---|---|
39 | 39 |
return name, path, args, kwargs |
40 | 40 | |
41 | 41 |
def to_python(self, value): |
42 |
value = super(UniqueBooleanField, self).to_python(value)
|
|
42 |
value = super().to_python(value) |
|
43 | 43 |
if value is None: |
44 | 44 |
return False |
45 | 45 |
return value |
46 | 46 | |
47 | 47 |
def get_db_prep_value(self, value, connection, prepared=False): |
48 |
value = super(UniqueBooleanField, self).get_db_prep_value(value, connection, prepared=prepared)
|
|
48 |
value = super().get_db_prep_value(value, connection, prepared=prepared) |
|
49 | 49 |
if value is False: |
50 | 50 |
return None |
51 | 51 |
return value |
src/authentic2/a2_rbac/management.py | ||
---|---|---|
29 | 29 |
Role = get_role_model() |
30 | 30 | |
31 | 31 |
if app_settings.MANAGED_CONTENT_TYPES == (): |
32 |
Role.objects.filter(slug='a2-managers-of-{ou.slug}'.format(ou=ou)).delete()
|
|
32 |
Role.objects.filter(slug=f'a2-managers-of-{ou.slug}').delete()
|
|
33 | 33 |
else: |
34 | 34 |
ou_admin_role = ou.get_admin_role() |
35 | 35 |
src/authentic2/a2_rbac/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 | |
... | ... | |
210 | 207 |
), |
211 | 208 |
migrations.AlterUniqueTogether( |
212 | 209 |
name='organizationalunit', |
213 |
unique_together=set([('name',), ('slug',)]),
|
|
210 |
unique_together={('name',), ('slug',)},
|
|
214 | 211 |
), |
215 | 212 |
migrations.AlterUniqueTogether( |
216 | 213 |
name='roleattribute', |
217 |
unique_together=set([('role', 'name', 'kind', 'value')]),
|
|
214 |
unique_together={('role', 'name', 'kind', 'value')},
|
|
218 | 215 |
), |
219 | 216 |
migrations.AlterUniqueTogether( |
220 | 217 |
name='role', |
221 |
unique_together=set([('slug', 'service'), ('slug', 'admin_scope_ct', 'admin_scope_id', 'ou')]),
|
|
218 |
unique_together={('slug', 'service'), ('slug', 'admin_scope_ct', 'admin_scope_id', 'ou')},
|
|
222 | 219 |
), |
223 | 220 |
] |
src/authentic2/a2_rbac/migrations/0002_role_external_id.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/a2_rbac/migrations/0003_partial_unique_index_on_name_and_slug.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
from authentic2.migrations import CreatePartialIndexes |
src/authentic2/a2_rbac/migrations/0004_auto_20150523_0028.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 | |
... | ... | |
21 | 18 |
), |
22 | 19 |
migrations.AlterUniqueTogether( |
23 | 20 |
name='role', |
24 |
unique_together=set([]),
|
|
21 |
unique_together=set(), |
|
25 | 22 |
), |
26 | 23 |
] |
src/authentic2/a2_rbac/migrations/0005_auto_20150526_1406.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/a2_rbac/migrations/0006_auto_20150619_1056.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/a2_rbac/migrations/0007_auto_20150708_1337.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/a2_rbac/migrations/0008_auto_20150810_1953.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/a2_rbac/migrations/0009_partial_unique_index_on_permission.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
from authentic2.migrations import CreatePartialIndexes |
src/authentic2/a2_rbac/migrations/0010_auto_20160209_1417.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from collections import defaultdict |
5 | 2 | |
6 | 3 |
from django.db import migrations |
... | ... | |
26 | 23 |
children = set() |
27 | 24 |
for role in duplicates: |
28 | 25 |
members |= set(role.members.all()) |
29 |
parents |= set(rp.parent for rp in RoleParenting.objects.filter(child=role, direct=True))
|
|
30 |
children |= set(rp.child for rp in RoleParenting.objects.filter(parent=role, direct=True))
|
|
26 |
parents |= {rp.parent for rp in RoleParenting.objects.filter(child=role, direct=True)}
|
|
27 |
children |= {rp.child for rp in RoleParenting.objects.filter(parent=role, direct=True)}
|
|
31 | 28 |
duplicates[0].members = members |
32 | 29 |
for parent in parents: |
33 | 30 |
RoleParenting.objects.get_or_crate(parent=parent, child=duplicates[0], direct=True) |
src/authentic2/a2_rbac/migrations/0011_auto_20160209_1511.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 | |
... | ... | |
13 | 10 |
operations = [ |
14 | 11 |
migrations.AlterUniqueTogether( |
15 | 12 |
name='role', |
16 |
unique_together=set([('admin_scope_ct', 'admin_scope_id')]),
|
|
13 |
unique_together={('admin_scope_ct', 'admin_scope_id')},
|
|
17 | 14 |
), |
18 | 15 |
] |
src/authentic2/a2_rbac/migrations/0013_auto_20170629_0007.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 | |
... | ... | |
13 | 10 |
operations = [ |
14 | 11 |
migrations.AlterUniqueTogether( |
15 | 12 |
name='roleparenting', |
16 |
unique_together=set([('parent', 'child', 'direct')]),
|
|
13 |
unique_together={('parent', 'child', 'direct')},
|
|
17 | 14 |
), |
18 | 15 |
migrations.AlterIndexTogether( |
19 | 16 |
name='roleparenting', |
20 |
index_together=set([('child', 'parent', 'direct')]),
|
|
17 |
index_together={('child', 'parent', 'direct')},
|
|
21 | 18 |
), |
22 | 19 |
] |
src/authentic2/a2_rbac/migrations/0014_auto_20170711_1024.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/a2_rbac/migrations/0015_organizationalunit_validate_emails.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/a2_rbac/migrations/0016_auto_20171208_1429.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/a2_rbac/migrations/0017_organizationalunit_user_can_reset_password.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/a2_rbac/migrations/0018_organizationalunit_user_add_password_policy.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/a2_rbac/migrations/0019_organizationalunit_show_username.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.18 on 2019-03-08 10:22 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations, models |
6 | 4 |
src/authentic2/a2_rbac/migrations/0020_partial_unique_index_on_name.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
from authentic2.migrations import CreatePartialIndexes |
src/authentic2/a2_rbac/migrations/0021_auto_20200317_1514.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.18 on 2020-03-17 14:14 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations, models |
6 | 4 |
src/authentic2/a2_rbac/migrations/0022_auto_20200402_1101.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.18 on 2020-04-02 09:01 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
import django.core.validators |
6 | 4 |
from django.db import migrations, models |
src/authentic2/a2_rbac/migrations/0023_role_can_manage_members.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.18 on 2020-05-27 13:22 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations, models |
6 | 4 |
src/authentic2/a2_rbac/migrations/0024_fix_self_admin_perm.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.18 on 2020-05-12 08:58 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations |
6 | 4 |
src/authentic2/a2_rbac/models.py | ||
---|---|---|
148 | 148 |
and self.clean_unused_accounts_alert >= self.clean_unused_accounts_deletion |
149 | 149 |
): |
150 | 150 |
raise ValidationError(_('Deletion alert delay must be less than actual deletion delay.')) |
151 |
super(OrganizationalUnit, self).clean()
|
|
151 |
super().clean() |
|
152 | 152 | |
153 | 153 |
def get_admin_role(self): |
154 | 154 |
"""Get or create the generic admin role for this organizational |
155 | 155 |
unit. |
156 | 156 |
""" |
157 | 157 |
name = _('Managers of "{ou}"').format(ou=self) |
158 |
slug = '_a2-managers-of-{ou.slug}'.format(ou=self)
|
|
158 |
slug = f'_a2-managers-of-{self.slug}'
|
|
159 | 159 |
return Role.objects.get_admin_role( |
160 | 160 |
instance=self, |
161 | 161 |
name=name, |
... | ... | |
256 | 256 |
admin_role = self.__class__.objects.get_admin_role( |
257 | 257 |
self, |
258 | 258 |
name=_('Managers of role "{role}"').format(role=str(self)), |
259 |
slug='_a2-managers-of-role-{role}'.format(role=slugify(str(self))),
|
|
259 |
slug=f'_a2-managers-of-role-{slugify(str(self))}',
|
|
260 | 260 |
permissions=(view_user_perm,), |
261 | 261 |
self_administered=True, |
262 | 262 |
update_name=True, |
... | ... | |
270 | 270 |
errors = {} |
271 | 271 | |
272 | 272 |
with errorcollector(errors): |
273 |
super(Role, self).validate_unique(exclude=exclude)
|
|
273 |
super().validate_unique(exclude=exclude) |
|
274 | 274 | |
275 | 275 |
exclude = exclude or [] |
276 | 276 | |
... | ... | |
295 | 295 |
# Service roles can only be part of the same ou as the service |
296 | 296 |
if self.service: |
297 | 297 |
self.ou = self.service.ou |
298 |
result = super(Role, self).save(*args, **kwargs)
|
|
298 |
result = super().save(*args, **kwargs) |
|
299 | 299 |
self.get_admin_role(create=False) |
300 | 300 |
return result |
301 | 301 | |
... | ... | |
402 | 402 |
verbose_name_plural = _('role parenting relations') |
403 | 403 | |
404 | 404 |
def __str__(self): |
405 |
return '{0} {1}> {2}'.format(self.parent.name, '-' if self.direct else '~', self.child.name)
|
|
405 |
return '{} {}> {}'.format(self.parent.name, '-' if self.direct else '~', self.child.name)
|
|
406 | 406 | |
407 | 407 | |
408 | 408 |
class RoleAttribute(models.Model): |
src/authentic2/admin.py | ||
---|---|---|
44 | 44 | |
45 | 45 |
class CleanupAdminMixin(admin.ModelAdmin): |
46 | 46 |
def get_actions(self, request): |
47 |
actions = super(CleanupAdminMixin, self).get_actions(request)
|
|
47 |
actions = super().get_actions(request) |
|
48 | 48 |
if hasattr(self.model.objects.none(), 'cleanup'): |
49 | 49 |
actions['cleanup_action'] = cleanup_action, 'cleanup_action', cleanup_action.short_description |
50 | 50 |
return actions |
... | ... | |
192 | 192 |
`self.value()`. |
193 | 193 |
""" |
194 | 194 |
if self.value(): |
195 |
return queryset.filter(username__endswith=u'@' + self.value())
|
|
195 |
return queryset.filter(username__endswith='@' + self.value()) |
|
196 | 196 |
return queryset |
197 | 197 | |
198 | 198 | |
... | ... | |
215 | 215 |
fields = '__all__' |
216 | 216 | |
217 | 217 |
def __init__(self, *args, **kwargs): |
218 |
super(UserChangeForm, self).__init__(*args, **kwargs)
|
|
218 |
super().__init__(*args, **kwargs) |
|
219 | 219 |
f = self.fields.get('user_permissions', None) |
220 | 220 |
if f is not None: |
221 | 221 |
f.queryset = f.queryset.select_related('content_type') |
... | ... | |
276 | 276 |
) |
277 | 277 | |
278 | 278 |
def save(self, commit=True): |
279 |
user = super(UserCreationForm, self).save(commit=False)
|
|
279 |
user = super().save(commit=False) |
|
280 | 280 |
user.set_password(self.cleaned_data["password1"]) |
281 | 281 |
if commit: |
282 | 282 |
user.save() |
... | ... | |
305 | 305 |
actions = UserAdmin.actions + ['mark_as_inactive'] |
306 | 306 | |
307 | 307 |
def get_fieldsets(self, request, obj=None): |
308 |
fieldsets = deepcopy(super(AuthenticUserAdmin, self).get_fieldsets(request, obj))
|
|
308 |
fieldsets = deepcopy(super().get_fieldsets(request, obj)) |
|
309 | 309 |
if obj: |
310 | 310 |
if not request.user.is_superuser: |
311 | 311 |
fieldsets[2][1]['fields'] = filter(lambda x: x != 'is_superuser', fieldsets[2][1]['fields']) |
... | ... | |
342 | 342 |
qs = models.Attribute.objects.all() |
343 | 343 |
else: |
344 | 344 |
qs = models.Attribute.objects.filter(required=True) |
345 |
non_model_fields = set([a.name for a in qs]) - set(['first_name', 'last_name'])
|
|
345 |
non_model_fields = {a.name for a in qs} - {'first_name', 'last_name'}
|
|
346 | 346 |
fields = list(set(fields) - set(non_model_fields)) |
347 | 347 |
kwargs['fields'] = fields |
348 |
return super(AuthenticUserAdmin, self).get_form(request, obj=obj, **kwargs)
|
|
348 |
return super().get_form(request, obj=obj, **kwargs) |
|
349 | 349 | |
350 | 350 |
@transaction.atomic |
351 | 351 |
def mark_as_inactive(self, request, queryset): |
... | ... | |
361 | 361 | |
362 | 362 |
class AttributeForm(forms.ModelForm): |
363 | 363 |
def __init__(self, *args, **kwargs): |
364 |
super(AttributeForm, self).__init__(*args, **kwargs)
|
|
364 |
super().__init__(*args, **kwargs) |
|
365 | 365 |
choices = self.kind_choices() |
366 | 366 |
self.fields['kind'].choices = choices |
367 | 367 |
self.fields['kind'].widget = forms.Select(choices=choices) |
src/authentic2/api_mixins.py | ||
---|---|---|
28 | 28 |
default_code = 'conflict' |
29 | 29 | |
30 | 30 | |
31 |
class GetOrCreateMixinView(object):
|
|
31 |
class GetOrCreateMixinView: |
|
32 | 32 |
_lookup_object = None |
33 | 33 | |
34 | 34 |
def get_object(self): |
35 | 35 |
if self._lookup_object is not None: |
36 | 36 |
return self._lookup_object |
37 |
return super(GetOrCreateMixinView, self).get_object()
|
|
37 |
return super().get_object() |
|
38 | 38 | |
39 | 39 |
def _get_lookup_keys(self, name): |
40 | 40 |
return self.request.GET.getlist(name) |
... | ... | |
85 | 85 |
self._lookup_object = self._lookup_instance(update_or_create_keys) |
86 | 86 |
if self._lookup_object is not None: |
87 | 87 |
return self.partial_update(request, *args, **kwargs) |
88 |
return super(GetOrCreateMixinView, self).create(request, *args, **kwargs) |
|
88 |
return super().create(request, *args, **kwargs) |
src/authentic2/api_views.py | ||
---|---|---|
77 | 77 |
User = get_user_model() |
78 | 78 | |
79 | 79 | |
80 |
class HookMixin(object):
|
|
80 |
class HookMixin: |
|
81 | 81 |
def get_serializer(self, *args, **kwargs): |
82 |
serializer = super(HookMixin, self).get_serializer(*args, **kwargs)
|
|
82 |
serializer = super().get_serializer(*args, **kwargs) |
|
83 | 83 |
# if the serializer is a ListSerializer, we modify the child |
84 | 84 |
if hasattr(serializer, 'child'): |
85 | 85 |
hooks.call_hooks('api_modify_serializer', self, serializer.child) |
... | ... | |
89 | 89 | |
90 | 90 |
def get_object(self): |
91 | 91 |
hooks.call_hooks('api_modify_view_before_get_object', self) |
92 |
return super(HookMixin, self).get_object()
|
|
92 |
return super().get_object() |
|
93 | 93 | |
94 | 94 | |
95 | 95 |
class DjangoPermission(permissions.BasePermission): |
... | ... | |
106 | 106 |
return self |
107 | 107 | |
108 | 108 | |
109 |
class ExceptionHandlerMixin(object):
|
|
109 |
class ExceptionHandlerMixin: |
|
110 | 110 |
def handle_exception(self, exc): |
111 | 111 |
if hasattr(exc, 'detail'): |
112 | 112 |
exc.detail = { |
113 | 113 |
'result': 0, |
114 | 114 |
'errors': exc.detail, |
115 | 115 |
} |
116 |
return super(ExceptionHandlerMixin, self).handle_exception(exc)
|
|
116 |
return super().handle_exception(exc) |
|
117 | 117 |
else: |
118 |
response = super(ExceptionHandlerMixin, self).handle_exception(exc)
|
|
118 |
response = super().handle_exception(exc) |
|
119 | 119 |
response.data = { |
120 | 120 |
'result': 0, |
121 | 121 |
'errors': response.data, |
... | ... | |
182 | 182 |
return data |
183 | 183 | |
184 | 184 | |
185 |
class RpcMixin(object):
|
|
185 |
class RpcMixin: |
|
186 | 186 |
def post(self, request, format=None): |
187 | 187 |
serializer = self.get_serializer(data=request.data) |
188 | 188 |
if serializer.is_valid(): |
... | ... | |
373 | 373 |
hashed_password = serializers.CharField(max_length=128, required=False) |
374 | 374 | |
375 | 375 |
def __init__(self, *args, **kwargs): |
376 |
super(BaseUserSerializer, self).__init__(*args, **kwargs)
|
|
376 |
super().__init__(*args, **kwargs) |
|
377 | 377 | |
378 | 378 |
for at in Attribute.objects.all(): |
379 | 379 |
if at.name in self.fields: |
... | ... | |
408 | 408 |
password = validated_data.pop('password', None) |
409 | 409 |
hashed_password = validated_data.pop('hashed_password', None) |
410 | 410 |
self.check_perm('custom_user.add_user', validated_data.get('ou')) |
411 |
instance = super(BaseUserSerializer, self).create(validated_data)
|
|
411 |
instance = super().create(validated_data) |
|
412 | 412 |
# prevent update on a get_or_create |
413 | 413 |
if not getattr(instance, '_a2_created', True): |
414 | 414 |
return instance |
... | ... | |
466 | 466 |
self.check_perm('custom_user.change_user', validated_data.get('ou')) |
467 | 467 |
if validated_data.get('email') != instance.email and not validated_data.get('email_verified'): |
468 | 468 |
instance.email_verified = False |
469 |
super(BaseUserSerializer, self).update(instance, validated_data)
|
|
469 |
super().update(instance, validated_data) |
|
470 | 470 |
for key, value in attributes.items(): |
471 | 471 |
if is_verified.get(key): |
472 | 472 |
setattr(instance.verified_attributes, key, value) |
... | ... | |
582 | 582 |
return self.context['request'].user |
583 | 583 | |
584 | 584 |
def __init__(self, instance=None, **kwargs): |
585 |
super(RoleSerializer, self).__init__(instance, **kwargs)
|
|
585 |
super().__init__(instance, **kwargs) |
|
586 | 586 |
if self.instance: |
587 | 587 |
self.fields['ou'].read_only = True |
588 | 588 | |
... | ... | |
590 | 590 |
ou = validated_data.get('ou') |
591 | 591 |
# Creating roles also means being allowed to within the OU: |
592 | 592 |
if not self.user.has_ou_perm('a2_rbac.add_role', ou): |
593 |
raise PermissionDenied(u'User %s can\'t create role in OU %s' % (self.user, ou))
|
|
594 |
return super(RoleSerializer, self).create(validated_data)
|
|
593 |
raise PermissionDenied('User %s can\'t create role in OU %s' % (self.user, ou)) |
|
594 |
return super().create(validated_data) |
|
595 | 595 | |
596 | 596 |
def update(self, instance, validated_data): |
597 | 597 |
# Check role-updating permissions: |
598 | 598 |
if not self.user.has_perm('a2_rbac.change_role', obj=instance): |
599 |
raise PermissionDenied(u'User %s can\'t change role %s' % (self.user, instance))
|
|
600 |
super(RoleSerializer, self).update(instance, validated_data)
|
|
599 |
raise PermissionDenied('User %s can\'t change role %s' % (self.user, instance)) |
|
600 |
super().update(instance, validated_data) |
|
601 | 601 |
return instance |
602 | 602 | |
603 | 603 |
def partial_update(self, instance, validated_data): |
604 | 604 |
# Check role-updating permissions: |
605 | 605 |
if not self.user.has_perm('a2_rbac.change_role', obj=instance): |
606 |
raise PermissionDenied(u'User %s can\'t change role %s' % (self.user, instance))
|
|
607 |
super(RoleSerializer, self).partial_update(instance, validated_data)
|
|
606 |
raise PermissionDenied('User %s can\'t change role %s' % (self.user, instance)) |
|
607 |
super().partial_update(instance, validated_data) |
|
608 | 608 |
return instance |
609 | 609 | |
610 | 610 |
class Meta: |
... | ... | |
627 | 627 |
def __init__(self, *args, **kwargs): |
628 | 628 |
self.bound = kwargs.pop('bound') |
629 | 629 |
assert self.bound in ['upper', 'lesser'] |
630 |
super(IsoDateTimeField, self).__init__(*args, **kwargs)
|
|
630 |
super().__init__(*args, **kwargs) |
|
631 | 631 | |
632 | 632 |
def strptime(self, value, format): |
633 | 633 |
try: |
634 |
return super(IsoDateTimeField, self).strptime(value, format)
|
|
634 |
return super().strptime(value, format) |
|
635 | 635 |
except (NonExistentTimeError, AmbiguousTimeError): |
636 | 636 |
parsed = parse_datetime(value) |
637 | 637 |
possible = sorted( |
... | ... | |
657 | 657 |
raise NotImplementedError |
658 | 658 | |
659 | 659 |
def filter(self, qs, value): |
660 |
return super(IsoDateTimeFilter, self).filter(qs, value)
|
|
660 |
return super().filter(qs, value) |
|
661 | 661 | |
662 | 662 | |
663 | 663 |
class UsersFilter(FilterSet): |
... | ... | |
779 | 779 |
def check_perm(self, perm, ou): |
780 | 780 |
if ou: |
781 | 781 |
if not self.request.user.has_ou_perm(perm, ou): |
782 |
raise PermissionDenied(u'You do not have permission %s in %s' % (perm, ou))
|
|
782 |
raise PermissionDenied('You do not have permission %s in %s' % (perm, ou)) |
|
783 | 783 |
else: |
784 | 784 |
if not self.request.user.has_perm(perm): |
785 |
raise PermissionDenied(u'You do not have permission %s' % perm)
|
|
785 |
raise PermissionDenied('You do not have permission %s' % perm) |
|
786 | 786 | |
787 | 787 |
def perform_create(self, serializer): |
788 | 788 |
super().perform_create(serializer) |
... | ... | |
797 | 797 |
def perform_destroy(self, instance): |
798 | 798 |
self.check_perm('custom_user.delete_user', instance.ou) |
799 | 799 |
self.request.journal.record('manager.user.deletion', target_user=instance, api=True) |
800 |
super(UsersAPI, self).perform_destroy(instance)
|
|
800 |
super().perform_destroy(instance) |
|
801 | 801 | |
802 | 802 |
class SynchronizationSerializer(serializers.Serializer): |
803 | 803 |
known_uuids = serializers.ListField(child=serializers.CharField()) |
... | ... | |
896 | 896 | |
897 | 897 |
def perform_destroy(self, instance): |
898 | 898 |
if not self.request.user.has_perm(perm='a2_rbac.delete_role', obj=instance): |
899 |
raise PermissionDenied(u'User %s can\'t create role %s' % (self.request.user, instance))
|
|
899 |
raise PermissionDenied('User %s can\'t create role %s' % (self.request.user, instance)) |
|
900 | 900 |
self.request.journal.record('manager.role.deletion', role=instance, api=True) |
901 |
super(RolesAPI, self).perform_destroy(instance)
|
|
901 |
super().perform_destroy(instance) |
|
902 | 902 | |
903 | 903 |
def perform_create(self, serializer): |
904 | 904 |
super().perform_create(serializer) |
... | ... | |
911 | 911 | |
912 | 912 |
class RolesMembersAPI(UsersAPI): |
913 | 913 |
def initial(self, request, *args, **kwargs): |
914 |
super(RolesMembersAPI, self).initial(request, *args, **kwargs)
|
|
914 |
super().initial(request, *args, **kwargs) |
|
915 | 915 |
Role = get_role_model() |
916 | 916 |
self.role = get_object_or_404(Role, uuid=kwargs['role_uuid']) |
917 | 917 | |
... | ... | |
930 | 930 |
permission_classes = (permissions.IsAuthenticated,) |
931 | 931 | |
932 | 932 |
def initial(self, request, *args, **kwargs): |
933 |
super(RoleMembershipAPI, self).initial(request, *args, **kwargs)
|
|
933 |
super().initial(request, *args, **kwargs) |
|
934 | 934 |
Role = get_role_model() |
935 | 935 |
User = get_user_model() |
936 | 936 |
self.role = get_object_or_404(Role, uuid=kwargs['role_uuid']) |
... | ... | |
938 | 938 | |
939 | 939 |
def get(self, request, *args, **kwargs): |
940 | 940 |
if not request.user.has_perm('a2_rbac.view_role', obj=self.role): |
941 |
raise PermissionDenied(u'User not allowed to view role')
|
|
941 |
raise PermissionDenied('User not allowed to view role') |
|
942 | 942 |
if self.request.GET.get('nested', 'false').lower() in ('true', '1'): |
943 | 943 |
qs = self.role.all_members() |
944 | 944 |
else: |
... | ... | |
948 | 948 | |
949 | 949 |
def post(self, request, *args, **kwargs): |
950 | 950 |
if not request.user.has_perm('a2_rbac.manage_members_role', obj=self.role): |
951 |
raise PermissionDenied(u'User not allowed to manage role members')
|
|
951 |
raise PermissionDenied('User not allowed to manage role members') |
|
952 | 952 |
self.role.members.add(self.member) |
953 | 953 |
request.journal.record('manager.role.membership.grant', role=self.role, member=self.member, api=True) |
954 | 954 |
return Response( |
... | ... | |
957 | 957 | |
958 | 958 |
def delete(self, request, *args, **kwargs): |
959 | 959 |
if not request.user.has_perm('a2_rbac.manage_members_role', obj=self.role): |
960 |
raise PermissionDenied(u'User not allowed to manage role members')
|
|
960 |
raise PermissionDenied('User not allowed to manage role members') |
|
961 | 961 |
self.role.members.remove(self.member) |
962 | 962 |
request.journal.record( |
963 | 963 |
'manager.role.membership.removal', role=self.role, member=self.member, api=True |
... | ... | |
975 | 975 |
http_method_names = ['post', 'put', 'patch', 'delete'] |
976 | 976 | |
977 | 977 |
def initial(self, request, *args, **kwargs): |
978 |
super(RoleMembershipsAPI, self).initial(request, *args, **kwargs)
|
|
978 |
super().initial(request, *args, **kwargs) |
|
979 | 979 |
Role = get_role_model() |
980 | 980 |
User = get_user_model() |
981 | 981 |
self.role = get_object_or_404(Role, uuid=kwargs['role_uuid']) |
... | ... | |
984 | 984 |
perm = 'a2_rbac.manage_members_role' |
985 | 985 |
authorized = request.user.has_perm(perm, obj=self.role) |
986 | 986 |
if not authorized: |
987 |
raise PermissionDenied(u'User not allowed to manage role members')
|
|
987 |
raise PermissionDenied('User not allowed to manage role members') |
|
988 | 988 | |
989 | 989 |
if not isinstance(request.data, dict): |
990 | 990 |
raise ValidationError(_('Payload must be a dictionary')) |
src/authentic2/app_settings.py | ||
---|---|---|
20 | 20 |
from django.utils.translation import ugettext_lazy as _ |
21 | 21 | |
22 | 22 | |
23 |
class Setting(object):
|
|
23 |
class Setting: |
|
24 | 24 |
SENTINEL = object() |
25 | 25 | |
26 | 26 |
def __init__(self, default=SENTINEL, definition='', names=None): |
... | ... | |
35 | 35 |
return self.default != self.SENTINEL |
36 | 36 | |
37 | 37 | |
38 |
class AppSettings(object):
|
|
38 |
class AppSettings: |
|
39 | 39 |
def __init__(self, defaults): |
40 | 40 |
self.defaults = defaults |
41 | 41 |
src/authentic2/attribute_aggregator/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 | |
... | ... | |
472 | 469 |
), |
473 | 470 |
migrations.AlterUniqueTogether( |
474 | 471 |
name='useraliasinsource', |
475 |
unique_together=set([('name', 'source')]),
|
|
472 |
unique_together={('name', 'source')},
|
|
476 | 473 |
), |
477 | 474 |
migrations.AddField( |
478 | 475 |
model_name='attributeitem', |
src/authentic2/attribute_aggregator/migrations/0002_auto_20150409_1840.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/attribute_aggregator/migrations/0003_auto_20150526_2239.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/attribute_aggregator/migrations/0004_auto_20150915_2041.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/attribute_kinds.py | ||
---|---|---|
69 | 69 |
def __init__(self, **kwargs): |
70 | 70 |
self.allow_blank = kwargs.pop('allow_blank', False) |
71 | 71 |
self.trim_whitespace = kwargs.pop('trim_whitespace', True) |
72 |
super(DateRestField, self).__init__(**kwargs)
|
|
72 |
super().__init__(**kwargs) |
|
73 | 73 | |
74 | 74 |
def run_validation(self, data=empty): |
75 | 75 |
# Test for the empty string here so that it does not get validated, |
... | ... | |
79 | 79 |
if not self.allow_blank: |
80 | 80 |
self.fail('blank') |
81 | 81 |
return '' |
82 |
return super(DateRestField, self).run_validation(data)
|
|
82 |
return super().run_validation(data) |
|
83 | 83 | |
84 | 84 | |
85 | 85 |
class BirthdateWidget(DateWidget): |
... | ... | |
90 | 90 |
options['startDate'] = '1900-01-01' |
91 | 91 |
attrs['min'] = '1900-01-01' |
92 | 92 |
attrs['max'] = (datetime.date.today() - datetime.timedelta(days=1)).isoformat() |
93 |
super(BirthdateWidget, self).__init__(*args, **kwargs)
|
|
93 |
super().__init__(*args, **kwargs) |
|
94 | 94 | |
95 | 95 | |
96 | 96 |
def validate_birthdate(value): |
... | ... | |
158 | 158 |
def __init__(self, *args, **kwargs): |
159 | 159 |
kwargs['max_length'] = 30 |
160 | 160 |
kwargs.setdefault('help_text', _('ex.: 0699999999, +33 6 99 99 99 99')) |
161 |
super(PhoneNumberField, self).__init__(*args, **kwargs)
|
|
161 |
super().__init__(*args, **kwargs) |
|
162 | 162 | |
163 | 163 |
def clean(self, value): |
164 | 164 |
if value not in self.empty_values: |
... | ... | |
179 | 179 |
class FrPostcodeField(forms.CharField): |
180 | 180 |
def __init__(self, *args, **kwargs): |
181 | 181 |
kwargs.setdefault('help_text', _('ex.: 13260')) |
182 |
super(FrPostcodeField, self).__init__(*args, **kwargs)
|
|
182 |
super().__init__(*args, **kwargs) |
|
183 | 183 | |
184 | 184 |
def clean(self, value): |
185 |
value = super(FrPostcodeField, self).clean(value)
|
|
185 |
value = super().clean(value) |
|
186 | 186 |
if value not in self.empty_values: |
187 | 187 |
value = value.strip() |
188 | 188 |
validate_fr_postcode(value) |
... | ... | |
196 | 196 |
default_validators = [validate_fr_postcode] |
197 | 197 | |
198 | 198 | |
199 |
class ProfileImageFile(object):
|
|
199 |
class ProfileImageFile: |
|
200 | 200 |
def __init__(self, name): |
201 | 201 |
self.name = name |
202 | 202 | |
... | ... | |
370 | 370 |
default_validators = [validate_siret] |
371 | 371 | |
372 | 372 |
def to_python(self, value): |
373 |
value = super(SIRETField, self).to_python(value)
|
|
373 |
value = super().to_python(value) |
|
374 | 374 |
value = only_digits(value) |
375 | 375 |
return value |
376 | 376 |
src/authentic2/attributes_ng/engine.py | ||
---|---|---|
97 | 97 |
""" |
98 | 98 |
for source in get_sources(): |
99 | 99 |
for instance in source.get_instances(ctx): |
100 |
for attribute_name, attribute_description in source.get_attribute_names(instance, ctx): |
|
101 |
yield attribute_name, attribute_description |
|
100 |
yield from source.get_attribute_names(instance, ctx) |
|
102 | 101 | |
103 | 102 | |
104 | 103 |
def get_attributes(ctx): |
... | ... | |
110 | 109 |
""" |
111 | 110 |
source_and_instances = [] |
112 | 111 |
for source in get_sources(): |
113 |
source_and_instances.extend(((source, instance) for instance in source.get_instances(ctx)))
|
|
112 |
source_and_instances.extend((source, instance) for instance in source.get_instances(ctx))
|
|
114 | 113 |
source_and_instances = topological_sort(source_and_instances, ctx) |
115 | 114 |
ctx = ctx.copy() |
116 | 115 |
for source, instance in source_and_instances: |
src/authentic2/attributes_ng/sources/__init__.py | ||
---|---|---|
17 | 17 |
import abc |
18 | 18 | |
19 | 19 | |
20 |
class BaseAttributeSource(object, metaclass=abc.ABCMeta):
|
|
20 |
class BaseAttributeSource(metaclass=abc.ABCMeta): |
|
21 | 21 |
""" |
22 | 22 |
Base class for attribute sources |
23 | 23 |
""" |
src/authentic2/attributes_ng/sources/format.py | ||
---|---|---|
18 | 18 | |
19 | 19 |
from ...decorators import to_list |
20 | 20 | |
21 |
AUTHORIZED_KEYS = set(('name', 'label', 'template'))
|
|
21 |
AUTHORIZED_KEYS = {'name', 'label', 'template'}
|
|
22 | 22 | |
23 | 23 | |
24 | 24 |
@to_list |
src/authentic2/attributes_ng/sources/function.py | ||
---|---|---|
18 | 18 | |
19 | 19 |
from ...decorators import to_list |
20 | 20 | |
21 |
AUTHORIZED_KEYS = set(('name', 'label', 'dependencies', 'function'))
|
|
21 |
AUTHORIZED_KEYS = {'name', 'label', 'dependencies', 'function'}
|
|
22 | 22 | |
23 |
REQUIRED_KEYS = set(('name', 'dependencies', 'function'))
|
|
23 |
REQUIRED_KEYS = {'name', 'dependencies', 'function'}
|
|
24 | 24 | |
25 | 25 |
UNEXPECTED_KEYS_ERROR = '{0}: unexpected key(s) {1} in configuration' |
26 | 26 |
MISSING_KEYS_ERROR = '{0}: missing key(s) {1} in configuration' |
src/authentic2/auth2_auth/auth2_ssl/__init__.py | ||
---|---|---|
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 | 17 | |
18 |
class Plugin(object):
|
|
18 |
class Plugin: |
|
19 | 19 |
def get_apps(self): |
20 | 20 |
return [__name__] |
src/authentic2/auth2_auth/auth2_ssl/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/auth2_auth/auth2_ssl/migrations/0002_auto_20150409_1840.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/auth2_auth/auth2_ssl/migrations/0003_auto_20190614_1438.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.20 on 2019-06-14 12:38 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations |
6 | 4 |
src/authentic2/auth_migrations_18/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.core import validators |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
from django.utils import timezone |
src/authentic2/auth_migrations_18/0002_auto_20150323_1720.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
import django.core.validators |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/auth_migrations_18/0003_auto_20150410_1657.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations |
6 | 3 |
src/authentic2/auth_migrations_18/0004_user.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
import django.core.validators |
5 | 2 |
import django.utils.timezone |
6 | 3 |
from django.db import migrations, models |
src/authentic2/auth_migrations_18/0005_auto_20150526_2303.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
import django.contrib.auth.models |
5 | 2 |
import django.core.validators |
6 | 3 |
from django.db import migrations, models |
src/authentic2/authentication.py | ||
---|---|---|
27 | 27 |
from authentic2_idp_oidc.models import OIDCClient |
28 | 28 | |
29 | 29 | |
30 |
class OIDCUser(object):
|
|
30 |
class OIDCUser: |
|
31 | 31 |
"""Fake user class to return in case OIDC authentication""" |
32 | 32 | |
33 | 33 |
def __init__(self, oidc_client): |
... | ... | |
68 | 68 |
except OIDCClient.DoesNotExist: |
69 | 69 |
pass |
70 | 70 |
# try BasicAuthentication |
71 |
if ( |
|
72 |
'request' |
|
73 |
in inspect.signature(super(Authentic2Authentication, self).authenticate_credentials).parameters |
|
74 |
): |
|
71 |
if 'request' in inspect.signature(super().authenticate_credentials).parameters: |
|
75 | 72 |
# compatibility with DRF 3.4 |
76 |
return super(Authentic2Authentication, self).authenticate_credentials( |
|
77 |
userid, password, request=request |
|
78 |
) |
|
79 |
return super(Authentic2Authentication, self).authenticate_credentials(userid, password) |
|
73 |
return super().authenticate_credentials(userid, password, request=request) |
|
74 |
return super().authenticate_credentials(userid, password) |
src/authentic2/authenticators.py | ||
---|---|---|
34 | 34 |
logger = logging.getLogger(__name__) |
35 | 35 | |
36 | 36 | |
37 |
class BaseAuthenticator(object):
|
|
37 |
class BaseAuthenticator: |
|
38 | 38 |
def __init__(self, show_condition=None, **kwargs): |
39 | 39 |
self.show_condition = show_condition |
40 | 40 |
src/authentic2/backends/ldap_backend.py | ||
---|---|---|
412 | 412 |
if self.block.get('keep_password_in_session', False): |
413 | 413 |
self.keep_password_in_session(password) |
414 | 414 |
if self.block['keep_password']: |
415 |
if not super(LDAPUser, self).check_password(password):
|
|
416 |
super(LDAPUser, self).set_password(password)
|
|
415 |
if not super().check_password(password): |
|
416 |
super().set_password(password) |
|
417 | 417 |
self._changed = True |
418 | 418 |
else: |
419 |
if super(LDAPUser, self).has_usable_password():
|
|
419 |
if super().has_usable_password(): |
|
420 | 420 |
self.set_unusable_password() |
421 | 421 |
self._changed = True |
422 | 422 | |
... | ... | |
478 | 478 |
self._current_password = new_password |
479 | 479 |
self.keep_password_in_session(new_password) |
480 | 480 |
if self.block['keep_password']: |
481 |
super(LDAPUser, self).set_password(new_password)
|
|
481 |
super().set_password(new_password) |
|
482 | 482 |
else: |
483 | 483 |
self.set_unusable_password() |
484 | 484 | |
... | ... | |
515 | 515 |
if hasattr(self, 'keep_pk'): |
516 | 516 |
pk = self.pk |
517 | 517 |
self.pk = self.keep_pk |
518 |
super(LDAPUser, self).save(*args, **kwargs)
|
|
518 |
super().save(*args, **kwargs) |
|
519 | 519 |
if hasattr(self, 'keep_pk'): |
520 | 520 |
self.pk = pk |
521 | 521 | |
... | ... | |
527 | 527 |
return self.block.get('user_can_change_password', False) |
528 | 528 | |
529 | 529 | |
530 |
class LDAPBackend(object):
|
|
530 |
class LDAPBackend: |
|
531 | 531 |
_DEFAULTS = { |
532 | 532 |
'basedn': '', |
533 | 533 |
'binddn': '', |
... | ... | |
699 | 699 |
# 1.1 is special attribute meaning, "no attribute requested" |
700 | 700 |
results = conn.search_s(group_base_dn, ldap.SCOPE_SUBTREE, block['group_filter'], ['1.1']) |
701 | 701 |
results = cls.normalize_ldap_results(results) |
702 |
return set([group_dn for group_dn, attrs in results])
|
|
702 |
return {group_dn for group_dn, attrs in results}
|
|
703 | 703 | |
704 | 704 |
def authenticate(self, request=None, username=None, password=None, realm=None, ou=None): |
705 | 705 |
if username is None or password is None: |
... | ... | |
762 | 762 |
log.debug( |
763 | 763 |
'[%s] looking up dn for username %r using query %r', ldap_uri, username, query |
764 | 764 |
) |
765 |
results = conn.search_s(user_basedn, ldap.SCOPE_SUBTREE, query, [u'1.1'])
|
|
765 |
results = conn.search_s(user_basedn, ldap.SCOPE_SUBTREE, query, ['1.1']) |
|
766 | 766 |
results = self.normalize_ldap_results(results) |
767 | 767 |
# remove search references |
768 | 768 |
results = [result for result in results if result[0] is not None] |
... | ... | |
808 | 808 |
try: |
809 | 809 |
self.bind(block, conn) |
810 | 810 |
except Exception: |
811 |
log.exception(u'rebind failure after login bind')
|
|
811 |
log.exception('rebind failure after login bind') |
|
812 | 812 |
raise ldap.SERVER_DOWN |
813 | 813 |
break |
814 | 814 |
except ldap.INVALID_CREDENTIALS as e: |
... | ... | |
1180 | 1180 |
for key in at_mapping: |
1181 | 1181 |
if at_mapping[key] != 'dn': |
1182 | 1182 |
attributes.add(at_mapping[key]) |
1183 |
return list(set(attribute.lower() for attribute in attributes))
|
|
1183 |
return list({attribute.lower() for attribute in attributes})
|
|
1184 | 1184 | |
1185 | 1185 |
@classmethod |
1186 | 1186 |
def get_ppolicy_attributes(cls, block, conn, dn): |
... | ... | |
1188 | 1188 | |
1189 | 1189 |
def get_attributes(dn, attributes): |
1190 | 1190 |
try: |
1191 |
results = conn.search_s(dn, ldap.SCOPE_BASE, u'(objectclass=*)', attributes)
|
|
1191 |
results = conn.search_s(dn, ldap.SCOPE_BASE, '(objectclass=*)', attributes) |
|
1192 | 1192 |
except ldap.LDAPError as e: |
1193 | 1193 |
log.error('[%s] unable to retrieve attributes of dn %r: %r', ldap_uri, dn, e) |
1194 | 1194 |
return {} |
... | ... | |
1369 | 1369 |
decoded.append((attribute, urllib.parse.unquote(value))) |
1370 | 1370 |
else: |
1371 | 1371 |
decoded.append((attribute, force_text(value))) |
1372 |
filters = [filter_format(u'(%s=%s)', (a, b)) for a, b in decoded]
|
|
1373 |
return '(&{0})'.format(''.join(filters))
|
|
1372 |
filters = [filter_format('(%s=%s)', (a, b)) for a, b in decoded] |
|
1373 |
return '(&{})'.format(''.join(filters)) |
|
1374 | 1374 | |
1375 | 1375 |
def build_external_id(self, external_id_tuple, attributes): |
1376 | 1376 |
"""Build the exernal id for the user, use attribute that eventually |
... | ... | |
1529 | 1529 |
msgid = conn.search_ext(*args, serverctrls=[pg_ctrl], **kwargs) |
1530 | 1530 |
result_type, data, msgid, serverctrls = conn.result3(msgid) |
1531 | 1531 |
pg_ctrl.cookie = serverctrls[0].cookie |
1532 |
for dn, attrs in cls.normalize_ldap_results(data): |
|
1533 |
yield dn, attrs |
|
1532 |
yield from cls.normalize_ldap_results(data) |
|
1534 | 1533 | |
1535 | 1534 |
@classmethod |
1536 | 1535 |
def get_users(cls): |
1537 | 1536 |
for block in cls.get_config(): |
1538 | 1537 |
conn = cls.get_connection(block) |
1539 | 1538 |
if conn is None: |
1540 |
log.warning(u'unable to synchronize with LDAP servers %s', force_text(block['url']))
|
|
1539 |
log.warning('unable to synchronize with LDAP servers %s', force_text(block['url'])) |
|
1541 | 1540 |
continue |
1542 | 1541 |
cls.check_group_to_role_mappings(block) |
1543 | 1542 |
user_basedn = force_text(block.get('user_basedn') or block['basedn']) |
... | ... | |
1601 | 1600 |
@classmethod |
1602 | 1601 |
def ad_encoding(cls, s): |
1603 | 1602 |
'''Encode a string for AD consumption as a password''' |
1604 |
return (u'"{0}"'.format(s)).encode('utf-16-le')
|
|
1603 |
return (f'"{s}"').encode('utf-16-le')
|
|
1605 | 1604 | |
1606 | 1605 |
@classmethod |
1607 | 1606 |
def modify_password(cls, conn, block, dn, old_password, new_password): |
... | ... | |
1705 | 1704 |
yield conn |
1706 | 1705 |
else: |
1707 | 1706 |
if block['replicas']: |
1708 |
log.warning(u'admin bind failed on %s: %s', url, error)
|
|
1707 |
log.warning('admin bind failed on %s: %s', url, error) |
|
1709 | 1708 |
else: |
1710 |
log.error(u'admin bind failed on %s: %s', url, error)
|
|
1709 |
log.error('admin bind failed on %s: %s', url, error) |
|
1711 | 1710 | |
1712 | 1711 |
@classmethod |
1713 | 1712 |
def bind(cls, block, conn, credentials=()): |
src/authentic2/backends/models_backend.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import unicode_literals |
|
18 | 17 | |
19 | 18 |
import functools |
20 | 19 | |
... | ... | |
30 | 29 | |
31 | 30 |
def upn(username, realm): |
32 | 31 |
'''Build an UPN from a username and a realm''' |
33 |
return '{0}@{1}'.format(username, realm)
|
|
32 |
return f'{username}@{realm}'
|
|
34 | 33 | |
35 | 34 | |
36 | 35 |
PROXY_USER_MODEL = None |
src/authentic2/cbv.py | ||
---|---|---|
24 | 24 |
from .utils.views import csrf_token_check |
25 | 25 | |
26 | 26 | |
27 |
class ValidateCSRFMixin(object):
|
|
27 |
class ValidateCSRFMixin: |
|
28 | 28 |
"""Move CSRF token validation inside the form validation. |
29 | 29 | |
30 | 30 |
This mixin must always be the leftest one and if your class override |
... | ... | |
35 | 35 |
@method_decorator(csrf_exempt) |
36 | 36 |
@method_decorator(ensure_csrf_cookie) |
37 | 37 |
def dispatch(self, *args, **kwargs): |
38 |
return super(ValidateCSRFMixin, self).dispatch(*args, **kwargs)
|
|
38 |
return super().dispatch(*args, **kwargs) |
|
39 | 39 | |
40 | 40 |
def form_valid(self, *args, **kwargs): |
41 | 41 |
for form in args: |
... | ... | |
43 | 43 |
csrf_token_check(self.request, form) |
44 | 44 |
if not form.is_valid(): |
45 | 45 |
return self.form_invalid(form) |
46 |
return super(ValidateCSRFMixin, self).form_valid(*args, **kwargs)
|
|
46 |
return super().form_valid(*args, **kwargs) |
|
47 | 47 | |
48 | 48 | |
49 |
class RedirectToNextURLViewMixin(object):
|
|
49 |
class RedirectToNextURLViewMixin: |
|
50 | 50 |
def get_success_url(self): |
51 | 51 |
if REDIRECT_FIELD_NAME in self.request.GET: |
52 | 52 |
return self.request.GET[REDIRECT_FIELD_NAME] |
... | ... | |
78 | 78 |
}, |
79 | 79 |
status=303, |
80 | 80 |
) |
81 |
return super(NextURLViewMixin, self).dispatch(request, *args, **kwargs)
|
|
81 |
return super().dispatch(request, *args, **kwargs) |
|
82 | 82 | |
83 | 83 | |
84 |
class TemplateNamesMixin(object):
|
|
84 |
class TemplateNamesMixin: |
|
85 | 85 |
def get_template_names(self): |
86 | 86 |
if hasattr(self, 'template_names'): |
87 | 87 |
return self.template_names |
88 |
return super(TemplateNamesMixin, self).get_template_names()
|
|
88 |
return super().get_template_names() |
|
89 | 89 | |
90 | 90 | |
91 |
class HookMixin(object):
|
|
91 |
class HookMixin: |
|
92 | 92 |
def get_form(self): |
93 |
form = super(HookMixin, self).get_form()
|
|
93 |
form = super().get_form() |
|
94 | 94 |
hooks.call_hooks('front_modify_form', self, form) |
95 | 95 |
return form |
src/authentic2/compat_lasso.py | ||
---|---|---|
18 | 18 |
import lasso |
19 | 19 |
except ImportError: |
20 | 20 | |
21 |
class MockLasso(object):
|
|
21 |
class MockLasso: |
|
22 | 22 |
def __getattr__(self, key): |
23 | 23 |
if key[0].isupper(): |
24 | 24 |
return '' |
src/authentic2/context_processors.py | ||
---|---|---|
21 | 21 |
from .models import Service |
22 | 22 | |
23 | 23 | |
24 |
class UserFederations(object):
|
|
24 |
class UserFederations: |
|
25 | 25 |
'''Provide access to all federations of the current user''' |
26 | 26 | |
27 | 27 |
def __init__(self, request): |
... | ... | |
42 | 42 |
d['provider'] = provider |
43 | 43 |
d['links'].append(link) |
44 | 44 |
return d |
45 |
return super(UserFederations, self).__getattr__(name)
|
|
45 |
return super().__getattr__(name) |
|
46 | 46 | |
47 | 47 | |
48 | 48 |
__AUTHENTIC2_DISTRIBUTION = None |
src/authentic2/csv_import.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import unicode_literals |
|
18 | 17 | |
19 | 18 |
import csv |
20 | 19 |
import io |
... | ... | |
74 | 73 |
return attr.s(func, **kwargs) |
75 | 74 | |
76 | 75 | |
77 |
class UTF8Recoder(object):
|
|
76 |
class UTF8Recoder: |
|
78 | 77 |
def __init__(self, fd): |
79 | 78 |
self.fd = fd |
80 | 79 | |
... | ... | |
87 | 86 |
next = __next__ |
88 | 87 | |
89 | 88 | |
90 |
class UnicodeReader(object):
|
|
89 |
class UnicodeReader: |
|
91 | 90 |
def __init__(self, fd, dialect='excel', **kwargs): |
92 | 91 |
self.reader = csv.reader(UTF8Recoder(fd), dialect=dialect, **kwargs) |
93 | 92 | |
... | ... | |
101 | 100 |
next = __next__ |
102 | 101 | |
103 | 102 | |
104 |
class CsvImporter(object):
|
|
103 |
class CsvImporter: |
|
105 | 104 |
rows = None |
106 | 105 |
error = None |
107 | 106 |
error_description = None |
... | ... | |
114 | 113 |
input_fd = io.StringIO(fd_or_str) |
115 | 114 |
elif not hasattr(fd_or_str, 'read1'): |
116 | 115 |
try: |
117 |
input_fd = io.open(fd_or_str.fileno(), closefd=False, mode='rb')
|
|
116 |
input_fd = open(fd_or_str.fileno(), closefd=False, mode='rb') |
|
118 | 117 |
except Exception: |
119 | 118 |
try: |
120 | 119 |
fd_or_str.seek(0) |
... | ... | |
152 | 151 |
input_fd.seek(0) |
153 | 152 | |
154 | 153 |
if not hasattr(input_fd, 'readable'): |
155 |
input_fd = io.open(input_fd.fileno(), 'rb', closefd=False)
|
|
154 |
input_fd = open(input_fd.fileno(), 'rb', closefd=False) |
|
156 | 155 |
return io.TextIOWrapper(input_fd, encoding=encoding) |
157 | 156 | |
158 | 157 |
def parse_csv(input_fd): |
... | ... | |
188 | 187 | |
189 | 188 | |
190 | 189 |
@attrs |
191 |
class CsvHeader(object):
|
|
190 |
class CsvHeader: |
|
192 | 191 |
column = attrib() |
193 | 192 |
name = attrib(default='') |
194 | 193 |
field = attrib(default=False, converter=bool) |
... | ... | |
215 | 214 | |
216 | 215 | |
217 | 216 |
@attrs |
218 |
class Error(object):
|
|
217 |
class Error: |
|
219 | 218 |
code = attrib() |
220 | 219 |
description = attrib(default='', cmp=False) |
221 | 220 | |
... | ... | |
240 | 239 | |
241 | 240 |
SOURCE_NAME = '_source_name' |
242 | 241 |
SOURCE_ID = '_source_id' |
243 |
SOURCE_COLUMNS = set([SOURCE_NAME, SOURCE_ID])
|
|
242 |
SOURCE_COLUMNS = {SOURCE_NAME, SOURCE_ID}
|
|
244 | 243 |
ROLE_NAME = '_role_name' |
245 | 244 |
ROLE_SLUG = '_role_slug' |
246 | 245 |
PASSWORD_HASH = 'password_hash' |
... | ... | |
289 | 288 | |
290 | 289 | |
291 | 290 |
@attrs |
292 |
class CsvRow(object):
|
|
291 |
class CsvRow: |
|
293 | 292 |
line = attrib() |
294 | 293 |
cells = attrib(default=[]) |
295 | 294 |
errors = attrib(default=[]) |
... | ... | |
328 | 327 | |
329 | 328 | |
330 | 329 |
@attrs |
331 |
class CsvCell(object):
|
|
330 |
class CsvCell: |
|
332 | 331 |
line = attrib() |
333 | 332 |
header = attrib() |
334 | 333 |
value = attrib(default=None) |
... | ... | |
349 | 348 |
pass |
350 | 349 | |
351 | 350 | |
352 |
class UserCsvImporter(object):
|
|
351 |
class UserCsvImporter: |
|
353 | 352 |
csv_importer = None |
354 | 353 |
errors = None |
355 | 354 |
headers = None |
src/authentic2/custom_user/management/commands/changepassword.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import print_function, unicode_literals |
|
18 | 17 | |
19 | 18 |
import getpass |
20 | 19 |
src/authentic2/custom_user/management/commands/fix-attributes.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import print_function, unicode_literals |
|
18 | 17 | |
19 | 18 |
from django.core.management.base import BaseCommand |
20 | 19 |
src/authentic2/custom_user/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
import django.utils.timezone |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/custom_user/migrations/0002_auto_20150410_1823.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 | |
... | ... | |
8 | 5 |
class ThirdPartyAlterField(migrations.AlterField): |
9 | 6 |
def __init__(self, *args, **kwargs): |
10 | 7 |
self.app_label = kwargs.pop('app_label') |
11 |
super(ThirdPartyAlterField, self).__init__(*args, **kwargs)
|
|
8 |
super().__init__(*args, **kwargs) |
|
12 | 9 | |
13 | 10 |
def state_forwards(self, app_label, state): |
14 |
super(ThirdPartyAlterField, self).state_forwards(self.app_label, state)
|
|
11 |
super().state_forwards(self.app_label, state) |
|
15 | 12 | |
16 | 13 |
def database_forwards(self, app_label, schema_editor, from_state, to_state): |
17 | 14 |
if hasattr(from_state, 'clear_delayed_apps_cache'): |
18 | 15 |
from_state.clear_delayed_apps_cache() |
19 |
super(ThirdPartyAlterField, self).database_forwards( |
|
20 |
self.app_label, schema_editor, from_state, to_state |
|
21 |
) |
|
16 |
super().database_forwards(self.app_label, schema_editor, from_state, to_state) |
|
22 | 17 | |
23 | 18 |
def database_backwards(self, app_label, schema_editor, from_state, to_state): |
24 | 19 |
self.database_forwards(app_label, schema_editor, from_state, to_state) |
src/authentic2/custom_user/migrations/0003_auto_20150504_1410.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/custom_user/migrations/0004_user_ou.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/custom_user/migrations/0005_auto_20150522_1527.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/custom_user/migrations/0006_auto_20150527_1212.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/custom_user/migrations/0007_auto_20150610_1527.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/custom_user/migrations/0008_auto_20150617_1606.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
import django.utils.timezone |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/custom_user/migrations/0009_auto_20150810_1953.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/custom_user/migrations/0010_auto_20160307_1418.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/custom_user/migrations/0011_manual_attribute_values_for_name_fields.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations |
5 | 2 | |
6 | 3 |
src/authentic2/custom_user/migrations/0012_user_modified.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
import datetime |
5 | 2 | |
6 | 3 |
from django.db import migrations, models |
src/authentic2/custom_user/migrations/0013_user_email_verified.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/custom_user/migrations/0014_set_email_verified.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations |
5 | 2 | |
6 | 3 |
src/authentic2/custom_user/migrations/0015_auto_20170707_1653.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/custom_user/migrations/0016_auto_20180925_1107.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.12 on 2018-09-25 09:07 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations, models |
6 | 4 |
src/authentic2/custom_user/migrations/0017_auto_20200305_1645.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.18 on 2020-03-05 15:45 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations, models |
6 | 4 |
src/authentic2/custom_user/migrations/0018_user_last_account_deletion_alert.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.18 on 2020-03-17 14:16 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations, models |
6 | 4 |
src/authentic2/custom_user/migrations/0019_add_user_deleted.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.29 on 2020-04-21 13:38 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations, models |
6 | 4 |
src/authentic2/custom_user/migrations/0021_set_unusable_password.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.29 on 2020-11-02 21:52 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.contrib.auth.models import AbstractUser |
6 | 4 |
from django.db import migrations |
src/authentic2/custom_user/migrations/0025_user_deactivation.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.29 on 2021-02-09 09:37 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations, models |
6 | 4 |
src/authentic2/custom_user/models.py | ||
---|---|---|
1 |
# coding: utf-8 |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
... | ... | |
15 | 14 |
# You should have received a copy of the GNU Affero General Public License |
16 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 16 | |
18 |
from __future__ import unicode_literals |
|
19 | 17 | |
20 | 18 |
import base64 |
21 | 19 |
import datetime |
... | ... | |
60 | 58 |
yield value |
61 | 59 | |
62 | 60 | |
63 |
class Attributes(object):
|
|
61 |
class Attributes: |
|
64 | 62 |
def __init__(self, owner, verified=None): |
65 | 63 |
self.__dict__['owner'] = owner |
66 | 64 |
self.__dict__['verified'] = verified |
... | ... | |
112 | 110 |
return None |
113 | 111 | |
114 | 112 | |
115 |
class AttributesDescriptor(object):
|
|
113 |
class AttributesDescriptor: |
|
116 | 114 |
def __init__(self, verified=None): |
117 | 115 |
self.verified = verified |
118 | 116 | |
... | ... | |
120 | 118 |
return Attributes(obj, verified=self.verified) |
121 | 119 | |
122 | 120 | |
123 |
class IsVerified(object):
|
|
121 |
class IsVerified: |
|
124 | 122 |
def __init__(self, user): |
125 | 123 |
self.user = user |
126 | 124 | |
... | ... | |
129 | 127 |
return v is not None and v == getattr(self.user.verified_attributes, name, None) |
130 | 128 | |
131 | 129 | |
132 |
class IsVerifiedDescriptor(object):
|
|
130 |
class IsVerifiedDescriptor: |
|
133 | 131 |
def __get__(self, obj, objtype): |
134 | 132 |
return IsVerified(obj) |
135 | 133 | |
... | ... | |
249 | 247 |
errors = {} |
250 | 248 | |
251 | 249 |
with errorcollector(errors): |
252 |
super(User, self).validate_unique(exclude=exclude)
|
|
250 |
super().validate_unique(exclude=exclude) |
|
253 | 251 | |
254 | 252 |
exclude = exclude or [] |
255 | 253 | |
... | ... | |
335 | 333 | |
336 | 334 |
def save(self, *args, **kwargs): |
337 | 335 |
update_fields = kwargs.get('update_fields') |
338 |
rc = super(User, self).save(*args, **kwargs)
|
|
339 |
if not update_fields or not set(update_fields).isdisjoint(set(['first_name', 'last_name'])):
|
|
336 |
rc = super().save(*args, **kwargs) |
|
337 |
if not update_fields or not set(update_fields).isdisjoint({'first_name', 'last_name'}):
|
|
340 | 338 |
try: |
341 | 339 |
self.attributes.first_name |
342 | 340 |
except AttributeError: |
... | ... | |
359 | 357 |
def refresh_from_db(self, *args, **kwargs): |
360 | 358 |
if hasattr(self, '_a2_attributes_cache'): |
361 | 359 |
del self._a2_attributes_cache |
362 |
return super(User, self).refresh_from_db(*args, **kwargs)
|
|
360 |
return super().refresh_from_db(*args, **kwargs) |
|
363 | 361 | |
364 | 362 |
def mark_as_active(self): |
365 | 363 |
self.is_active = True |
src/authentic2/data_transfer.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import unicode_literals |
|
18 | 17 | |
19 | 18 |
import uuid |
20 | 19 |
from functools import wraps |
... | ... | |
68 | 67 |
obj.save() |
69 | 68 | |
70 | 69 | |
71 |
class ExportContext(object):
|
|
70 |
class ExportContext: |
|
72 | 71 |
_role_qs = None |
73 | 72 |
_ou_qs = None |
74 | 73 |
export_roles = None |
... | ... | |
130 | 129 |
return role |
131 | 130 | |
132 | 131 | |
133 |
class ImportContext(object):
|
|
132 |
class ImportContext: |
|
134 | 133 |
"""Holds information on how to perform the import. |
135 | 134 | |
136 | 135 |
ou_delete_orphans: if True any existing ou that is not found in the export will |
... | ... | |
172 | 171 |
self.set_ou = set_ou |
173 | 172 | |
174 | 173 | |
175 |
class RoleDeserializer(object):
|
|
174 |
class RoleDeserializer: |
|
176 | 175 |
def __init__(self, d, import_context): |
177 | 176 |
self._import_context = import_context |
178 | 177 |
self._obj = None |
... | ... | |
316 | 315 |
return created, deleted |
317 | 316 | |
318 | 317 | |
319 |
class ImportResult(object):
|
|
318 |
class ImportResult: |
|
320 | 319 |
def __init__(self): |
321 | 320 |
self.roles = {'created': [], 'updated': []} |
322 | 321 |
self.ous = {'created': [], 'updated': []} |
src/authentic2/decorators.py | ||
---|---|---|
125 | 125 |
return instance |
126 | 126 | |
127 | 127 | |
128 |
class CacheDecoratorBase(object):
|
|
128 |
class CacheDecoratorBase: |
|
129 | 129 |
"""Base class to build cache decorators. |
130 | 130 | |
131 | 131 |
It helps for building keys from function arguments. |
... | ... | |
140 | 140 |
if args: |
141 | 141 |
# Case of a decorator used directly |
142 | 142 |
return cls(**kwargs)(args[0]) |
143 |
return super(CacheDecoratorBase, cls).__new__(cls)
|
|
143 |
return super().__new__(cls) |
|
144 | 144 | |
145 | 145 |
def __init__(self, timeout=None, hostname_vary=True, args=None, kwargs=None): |
146 | 146 |
self.timeout = timeout |
... | ... | |
199 | 199 |
for kw, arg in sorted(kwargs.items(), key=lambda x: x[0]): |
200 | 200 |
if kw not in self.kwargs: |
201 | 201 |
continue |
202 |
parts.append(u'%s-%s' % (str(kw), str(arg)))
|
|
202 |
parts.append('%s-%s' % (str(kw), str(arg))) |
|
203 | 203 |
return '|'.join(parts) |
204 | 204 | |
205 | 205 | |
206 |
class SimpleDictionnaryCacheMixin(object):
|
|
206 |
class SimpleDictionnaryCacheMixin: |
|
207 | 207 |
"""Default implementations of set, get and delete for a cache implemented |
208 | 208 |
using a dictionary. The dictionnary must be returned by a property named |
209 | 209 |
'cache'. |
... | ... | |
226 | 226 |
class GlobalCache(SimpleDictionnaryCacheMixin, CacheDecoratorBase): |
227 | 227 |
def __init__(self, *args, **kwargs): |
228 | 228 |
self.cache = {} |
229 |
super(GlobalCache, self).__init__(*args, **kwargs)
|
|
229 |
super().__init__(*args, **kwargs) |
|
230 | 230 | |
231 | 231 | |
232 | 232 |
class RequestCache(SimpleDictionnaryCacheMixin, CacheDecoratorBase): |
... | ... | |
252 | 252 |
self.delete(key) |
253 | 253 | |
254 | 254 | |
255 |
class PickleCacheMixin(object):
|
|
255 |
class PickleCacheMixin: |
|
256 | 256 |
def set(self, key, value): |
257 | 257 |
value, tstamp = value |
258 | 258 |
value = base64.b64encode(pickle.dumps(value)).decode('ascii') |
259 |
super(PickleCacheMixin, self).set(key, (value, tstamp))
|
|
259 |
super().set(key, (value, tstamp)) |
|
260 | 260 | |
261 | 261 |
def get(self, key): |
262 |
value = super(PickleCacheMixin, self).get(key)
|
|
262 |
value = super().get(key) |
|
263 | 263 |
if value[0] is not None: |
264 | 264 |
value, tstamp = value |
265 | 265 |
try: |
... | ... | |
283 | 283 |
request = middleware.StoreRequestMiddleware.get_request() |
284 | 284 |
if request: |
285 | 285 |
request.session.modified = True |
286 |
return super(SessionCache, self).set(key, value)
|
|
286 |
return super().set(key, value) |
|
287 | 287 | |
288 | 288 |
def clear(self): |
289 | 289 |
request = middleware.StoreRequestMiddleware.get_request() |
290 | 290 |
if request: |
291 | 291 |
request.session.modified = True |
292 |
return super(SessionCache, self).clear()
|
|
292 |
return super().clear() |
|
293 | 293 | |
294 | 294 | |
295 | 295 |
@contextmanager |
src/authentic2/exponential_retry_timeout.py | ||
---|---|---|
21 | 21 |
from django.core.cache import cache |
22 | 22 | |
23 | 23 | |
24 |
class ExponentialRetryTimeout(object):
|
|
24 |
class ExponentialRetryTimeout: |
|
25 | 25 |
FACTOR = 1.8 |
26 | 26 |
DURATION = 0.8 |
27 | 27 |
MAX_DURATION = 3600 # max 1 hour |
... | ... | |
66 | 66 |
if not self.duration: |
67 | 67 |
return |
68 | 68 |
cache.delete(key) |
69 |
self.logger.debug(u'success for %s', keys)
|
|
69 |
self.logger.debug('success for %s', keys) |
|
70 | 70 | |
71 | 71 |
def failure(self, *keys): |
72 | 72 |
"""Signal an action failure, augment the exponential backoff one level.""" |
... | ... | |
83 | 83 |
duration = min(self.duration * self.factor ** level, self.max_duration) |
84 | 84 |
next_time += duration |
85 | 85 |
cache.set(key, (level, next_time), self.cache_duration) |
86 |
self.logger.debug(u'failure for %s, level: %s, next_time: %s', keys, level, next_time) |
|
86 |
self.logger.debug('failure for %s, level: %s, next_time: %s', keys, level, next_time) |
src/authentic2/forms/authentication.py | ||
---|---|---|
51 | 51 |
def __init__(self, *args, **kwargs): |
52 | 52 |
preferred_ous = kwargs.pop('preferred_ous', []) |
53 | 53 | |
54 |
super(AuthenticationForm, self).__init__(*args, **kwargs)
|
|
54 |
super().__init__(*args, **kwargs) |
|
55 | 55 | |
56 | 56 |
self.exponential_backoff = ExponentialRetryTimeout( |
57 | 57 |
key_prefix='login-exp-backoff-', |
... | ... | |
132 | 132 | |
133 | 133 |
@property |
134 | 134 |
def media(self): |
135 |
media = super(AuthenticationForm, self).media
|
|
135 |
media = super().media |
|
136 | 136 |
media = media + Media(js=['authentic2/js/js_seconds_until.js']) |
137 | 137 |
if app_settings.A2_LOGIN_FORM_OU_SELECTOR: |
138 | 138 |
media = media + Media(js=['authentic2/js/ou_selector.js']) |
src/authentic2/forms/fields.py | ||
---|---|---|
45 | 45 | |
46 | 46 |
def __init__(self, *args, **kwargs): |
47 | 47 |
kwargs['help_text'] = password_help_text() |
48 |
super(NewPasswordField, self).__init__(*args, **kwargs)
|
|
48 |
super().__init__(*args, **kwargs) |
|
49 | 49 | |
50 | 50 | |
51 | 51 |
class CheckPasswordField(CharField): |
... | ... | |
63 | 63 |
'match': _('Passwords match.'), |
64 | 64 |
'nomatch': _('Passwords do not match.'), |
65 | 65 |
} |
66 |
super(CheckPasswordField, self).__init__(*args, **kwargs)
|
|
66 |
super().__init__(*args, **kwargs) |
|
67 | 67 | |
68 | 68 | |
69 | 69 |
class ProfileImageField(FileField): |
... | ... | |
75 | 75 | |
76 | 76 |
def clean(self, data, initial=None): |
77 | 77 |
if data is FILE_INPUT_CONTRADICTION or data is False or data is None: |
78 |
return super(ProfileImageField, self).clean(data, initial=initial)
|
|
78 |
return super().clean(data, initial=initial) |
|
79 | 79 |
# we have a file |
80 | 80 |
try: |
81 | 81 |
with warnings.catch_warnings(): |
82 | 82 |
image = PIL.Image.open(io.BytesIO(data.read())) |
83 |
except (IOError, PIL.Image.DecompressionBombWarning):
|
|
83 |
except (OSError, PIL.Image.DecompressionBombWarning):
|
|
84 | 84 |
raise ValidationError(_('The image is not valid')) |
85 | 85 |
image = self.normalize_image(image) |
86 | 86 |
new_data = self.file_from_image(image, data.name) |
87 |
return super(ProfileImageField, self).clean(new_data, initial=initial)
|
|
87 |
return super().clean(new_data, initial=initial) |
|
88 | 88 | |
89 | 89 |
def file_from_image(self, image, name=None): |
90 | 90 |
output = io.BytesIO() |
src/authentic2/forms/mixins.py | ||
---|---|---|
20 | 20 |
from django.utils.translation import ugettext as _ |
21 | 21 | |
22 | 22 | |
23 |
class LockedFieldFormMixin(object):
|
|
23 |
class LockedFieldFormMixin: |
|
24 | 24 |
def __init__(self, *args, **kwargs): |
25 |
super(LockedFieldFormMixin, self).__init__(*args, **kwargs)
|
|
25 |
super().__init__(*args, **kwargs) |
|
26 | 26 |
self.__lock_fields() |
27 | 27 | |
28 | 28 |
def __lock_fields(self): |
src/authentic2/forms/passwords.py | ||
---|---|---|
87 | 87 |
logger.info('password reset failed for user "%r": account is disabled', user) |
88 | 88 |
utils.send_templated_mail(user, ['authentic2/password_reset_refused']) |
89 | 89 |
if not self.users.exists() and email: |
90 |
logger.info(u'password reset request for "%s", no user found', email)
|
|
90 |
logger.info('password reset request for "%s", no user found', email) |
|
91 | 91 |
if getattr(settings, 'REGISTRATION_OPEN', True): |
92 | 92 |
ctx = { |
93 | 93 |
'registration_url': utils.make_url('registration_register', absolute=True), |
... | ... | |
103 | 103 |
successfully changed.""" |
104 | 104 | |
105 | 105 |
def save(self, commit=True): |
106 |
ret = super(PasswordResetMixin, self).save(commit=commit)
|
|
106 |
ret = super().save(commit=commit) |
|
107 | 107 |
if commit: |
108 | 108 |
models.PasswordReset.objects.filter(user=self.user).delete() |
109 | 109 |
else: |
... | ... | |
118 | 118 |
return ret |
119 | 119 | |
120 | 120 | |
121 |
class NotifyOfPasswordChange(object):
|
|
121 |
class NotifyOfPasswordChange: |
|
122 | 122 |
def save(self, commit=True): |
123 |
user = super(NotifyOfPasswordChange, self).save(commit=commit)
|
|
123 |
user = super().save(commit=commit) |
|
124 | 124 |
if user.email: |
125 | 125 |
ctx = { |
126 | 126 |
'user': user, |
src/authentic2/forms/profile.py | ||
---|---|---|
33 | 33 | |
34 | 34 |
def __init__(self, *args, **kwargs): |
35 | 35 |
self.user = kwargs.pop('user') |
36 |
super(DeleteAccountForm, self).__init__(*args, **kwargs)
|
|
36 |
super().__init__(*args, **kwargs) |
|
37 | 37 | |
38 | 38 |
def clean_password(self): |
39 | 39 |
password = self.cleaned_data.get('password') |
... | ... | |
47 | 47 | |
48 | 48 |
def __init__(self, user, *args, **kwargs): |
49 | 49 |
self.user = user |
50 |
super(EmailChangeFormNoPassword, self).__init__(*args, **kwargs)
|
|
50 |
super().__init__(*args, **kwargs) |
|
51 | 51 | |
52 | 52 | |
53 | 53 |
class EmailChangeForm(EmailChangeFormNoPassword): |
... | ... | |
93 | 93 |
# helper data for LockedFieldFormMixin |
94 | 94 |
if atv.verified: |
95 | 95 |
self.locked_fields.add(name) |
96 |
super(BaseUserForm, self).__init__(*args, **kwargs)
|
|
96 |
super().__init__(*args, **kwargs) |
|
97 | 97 | |
98 | 98 |
def is_field_locked(self, name): |
99 | 99 |
# helper method for LockedFieldFormMixin |
... | ... | |
111 | 111 |
setattr(self.instance.attributes, name, value) |
112 | 112 | |
113 | 113 |
def save(self, commit=True): |
114 |
result = super(BaseUserForm, self).save(commit=commit)
|
|
114 |
result = super().save(commit=commit) |
|
115 | 115 |
if commit: |
116 | 116 |
self.save_attributes() |
117 | 117 |
else: |
src/authentic2/forms/registration.py | ||
---|---|---|
41 | 41 |
email = ValidatedEmailField(label=_('Email')) |
42 | 42 | |
43 | 43 |
def __init__(self, *args, **kwargs): |
44 |
super(RegistrationForm, self).__init__(*args, **kwargs)
|
|
44 |
super().__init__(*args, **kwargs) |
|
45 | 45 |
attributes = {a.name: a for a in models.Attribute.objects.all()} |
46 | 46 |
for field in app_settings.A2_PRE_REGISTRATION_FIELDS: |
47 | 47 |
if field in ('first_name', 'last_name'): |
... | ... | |
127 | 127 |
def save(self, commit=True): |
128 | 128 |
self.instance.email_verified = True |
129 | 129 |
self.instance.is_active = True |
130 |
user = super(RegistrationCompletionFormNoPassword, self).save(commit=commit)
|
|
130 |
user = super().save(commit=commit) |
|
131 | 131 |
if commit and app_settings.A2_REGISTRATION_GROUPS: |
132 | 132 |
groups = [] |
133 | 133 |
for name in app_settings.A2_REGISTRATION_GROUPS: |
src/authentic2/forms/utils.py | ||
---|---|---|
28 | 28 |
request = StoreRequestMiddleware.get_request() |
29 | 29 |
if not next_url and request: |
30 | 30 |
next_url = request.GET.get(REDIRECT_FIELD_NAME) |
31 |
super(NextUrlFormMixin, self).__init__(*args, **kwargs)
|
|
31 |
super().__init__(*args, **kwargs) |
|
32 | 32 |
if next_url: |
33 | 33 |
self.fields['next_url'].initial = next_url |
src/authentic2/forms/widgets.py | ||
---|---|---|
101 | 101 |
CLEAR_BTN_TEMPLATE = """<span class="add-on"><i class="icon-remove"></i></span>""" |
102 | 102 | |
103 | 103 | |
104 |
class PickerWidgetMixin(object):
|
|
104 |
class PickerWidgetMixin: |
|
105 | 105 |
class Media: |
106 | 106 |
css = { |
107 | 107 |
'all': ('css/datetimepicker.css',), |
... | ... | |
134 | 134 |
lambda x: DATE_FORMAT_JS_PY_MAPPING[x.group()], date_format |
135 | 135 |
) |
136 | 136 | |
137 |
super(PickerWidgetMixin, self).__init__(attrs, format=self.format)
|
|
137 |
super().__init__(attrs, format=self.format) |
|
138 | 138 | |
139 | 139 |
def get_format(self): |
140 | 140 |
format = get_format(self.format_name)[0] |
... | ... | |
146 | 146 |
attrs = attrs or {} |
147 | 147 |
final_attrs = self.build_attrs(attrs) |
148 | 148 |
final_attrs['class'] = "controls input-append date" |
149 |
rendered_widget = super(PickerWidgetMixin, self).render( |
|
150 |
name, value, attrs=final_attrs, renderer=renderer |
|
151 |
) |
|
149 |
rendered_widget = super().render(name, value, attrs=final_attrs, renderer=renderer) |
|
152 | 150 | |
153 | 151 |
# if not set, autoclose have to be true. |
154 | 152 |
self.options.setdefault('autoclose', True) |
... | ... | |
198 | 196 |
# Set the default options to show only the datepicker object |
199 | 197 |
options['format'] = options.get('format', self.get_format()) |
200 | 198 | |
201 |
super(DateTimeWidget, self).__init__(attrs, options, usel10n)
|
|
199 |
super().__init__(attrs, options, usel10n) |
|
202 | 200 | |
203 | 201 | |
204 | 202 |
class DateWidget(PickerWidgetMixin, DateInput): |
... | ... | |
222 | 220 |
options['minView'] = options.get('minView', 2) |
223 | 221 |
options['format'] = options.get('format', self.get_format()) |
224 | 222 | |
225 |
super(DateWidget, self).__init__(attrs, options, usel10n)
|
|
223 |
super().__init__(attrs, options, usel10n) |
|
226 | 224 | |
227 | 225 |
def format_value(self, value): |
228 | 226 |
if value is not None: |
... | ... | |
251 | 249 |
options['maxView'] = options.get('maxView', 1) |
252 | 250 |
options['format'] = options.get('format', self.get_format()) |
253 | 251 | |
254 |
super(TimeWidget, self).__init__(attrs, options, usel10n)
|
|
252 |
super().__init__(attrs, options, usel10n) |
|
255 | 253 | |
256 | 254 | |
257 | 255 |
class PasswordInput(BasePasswordInput): |
... | ... | |
263 | 261 |
css = {'all': ('authentic2/css/password.css',)} |
264 | 262 | |
265 | 263 |
def render(self, name, value, attrs=None, renderer=None): |
266 |
output = super(PasswordInput, self).render(name, value, attrs=attrs, renderer=renderer)
|
|
264 |
output = super().render(name, value, attrs=attrs, renderer=renderer) |
|
267 | 265 |
if attrs and app_settings.A2_PASSWORD_POLICY_SHOW_LAST_CHAR: |
268 | 266 |
_id = attrs.get('id') |
269 | 267 |
if _id: |
... | ... | |
276 | 274 |
if attrs is None: |
277 | 275 |
attrs = {} |
278 | 276 |
attrs['autocomplete'] = 'new-password' |
279 |
output = super(NewPasswordInput, self).render(name, value, attrs=attrs, renderer=renderer)
|
|
277 |
output = super().render(name, value, attrs=attrs, renderer=renderer) |
|
280 | 278 |
if attrs: |
281 | 279 |
_id = attrs.get('id') |
282 | 280 |
if _id: |
... | ... | |
291 | 289 |
if attrs is None: |
292 | 290 |
attrs = {} |
293 | 291 |
attrs['autocomplete'] = 'new-password' |
294 |
output = super(CheckPasswordInput, self).render(name, value, attrs=attrs, renderer=renderer)
|
|
292 |
output = super().render(name, value, attrs=attrs, renderer=renderer) |
|
295 | 293 |
if attrs: |
296 | 294 |
_id = attrs.get('id') |
297 | 295 |
if _id and _id.endswith('2'): |
... | ... | |
315 | 313 |
def __init__(self, *args, **kwargs): |
316 | 314 |
attrs = kwargs.pop('attrs', {}) |
317 | 315 |
attrs['accept'] = 'image/*' |
318 |
super(ProfileImageInput, self).__init__(*args, attrs=attrs, **kwargs)
|
|
316 |
super().__init__(*args, attrs=attrs, **kwargs) |
|
319 | 317 | |
320 | 318 | |
321 | 319 |
class DatalistTextInput(TextInput): |
322 | 320 |
def __init__(self, name='', data=(), attrs=None): |
323 |
super(DatalistTextInput, self).__init__(attrs)
|
|
321 |
super().__init__(attrs) |
|
324 | 322 |
self.data = data |
325 | 323 |
self.name = 'list__%s' % name |
326 | 324 |
self.attrs.update({'list': self.name}) |
327 | 325 | |
328 | 326 |
def render(self, name, value, attrs=None, renderer=None): |
329 |
output = super(DatalistTextInput, self).render(name, value, attrs=attrs, renderer=renderer)
|
|
327 |
output = super().render(name, value, attrs=attrs, renderer=renderer) |
|
330 | 328 |
datalist = '<datalist id="%s">' % self.name |
331 | 329 |
for element in self.data: |
332 | 330 |
datalist += '<option value="%s">' % element |
... | ... | |
354 | 352 |
) |
355 | 353 | |
356 | 354 |
def get_context(self, *args, **kwargs): |
357 |
context = super(EmailInput, self).get_context(*args, **kwargs)
|
|
355 |
context = super().get_context(*args, **kwargs) |
|
358 | 356 |
if app_settings.A2_SUGGESTED_EMAIL_DOMAINS: |
359 | 357 |
context['widget']['attrs']['data-suggested-domains'] = ':'.join( |
360 | 358 |
app_settings.A2_SUGGESTED_EMAIL_DOMAINS |
src/authentic2/hooks.py | ||
---|---|---|
56 | 56 |
except Exception: |
57 | 57 |
if getattr(settings, 'A2_HOOKS_PROPAGATE_EXCEPTIONS', False): |
58 | 58 |
raise |
59 |
logger.exception(u'exception while calling hook %s', hook)
|
|
59 |
logger.exception('exception while calling hook %s', hook) |
|
60 | 60 | |
61 | 61 | |
62 | 62 |
def call_hooks_first_result(hook_name, *args, **kwargs): |
... | ... | |
71 | 71 |
except Exception: |
72 | 72 |
if getattr(settings, 'A2_HOOKS_PROPAGATE_EXCEPTIONS', False): |
73 | 73 |
raise |
74 |
logger.exception(u'exception while calling hook %s', hook) |
|
74 |
logger.exception('exception while calling hook %s', hook) |
src/authentic2/idp/__init__.py | ||
---|---|---|
1 |
src/authentic2/idp/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/idp/migrations/0002_auto_20150526_2239.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/idp/migrations/0003_auto_20150915_2041.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/idp/saml/__init__.py | ||
---|---|---|
19 | 19 |
from django.core.checks import Tags, Warning, register |
20 | 20 | |
21 | 21 | |
22 |
class Plugin(object):
|
|
22 |
class Plugin: |
|
23 | 23 |
def check_origin(self, request, origin): |
24 | 24 |
from authentic2.cors import make_origin |
25 | 25 |
from authentic2.saml.models import LibertySession |
src/authentic2/idp/saml/app_settings.py | ||
---|---|---|
17 | 17 |
import sys |
18 | 18 | |
19 | 19 | |
20 |
class AppSettings(object):
|
|
20 |
class AppSettings: |
|
21 | 21 |
__DEFAULTS = dict( |
22 | 22 |
ENABLE=False, |
23 | 23 |
METADATA_OPTIONS={}, |
src/authentic2/idp/saml/backend.py | ||
---|---|---|
32 | 32 |
from authentic2.utils import Service |
33 | 33 | |
34 | 34 | |
35 |
class SamlBackend(object):
|
|
35 |
class SamlBackend: |
|
36 | 36 |
def __init__(self): |
37 | 37 |
self.logger = logging.getLogger(__name__) |
38 | 38 | |
... | ... | |
44 | 44 |
) |
45 | 45 |
ls = [] |
46 | 46 |
sessions = models.LibertySession.objects.filter(django_session_key=request.session.session_key) |
47 |
sessions_eids = set(session.provider_id for session in sessions)
|
|
47 |
sessions_eids = {session.provider_id for session in sessions}
|
|
48 | 48 |
all_policy = common.get_sp_options_policy_all() |
49 | 49 |
default_policy = common.get_sp_options_policy_default() |
50 | 50 |
queries = [] |
... | ... | |
99 | 99 |
def logout_list(self, request): |
100 | 100 |
all_sessions = models.LibertySession.objects.filter(django_session_key=request.session.session_key) |
101 | 101 |
self.logger.debug("all_sessions %r" % all_sessions) |
102 |
provider_ids = set([s.provider_id for s in all_sessions])
|
|
102 |
provider_ids = {s.provider_id for s in all_sessions}
|
|
103 | 103 |
self.logger.debug("provider_ids %r" % provider_ids) |
104 | 104 |
result = [] |
105 | 105 |
for provider_id in provider_ids: |
... | ... | |
109 | 109 |
provider = models.LibertyProvider.objects.get(entity_id=provider_id) |
110 | 110 |
name = provider.name |
111 | 111 |
except models.LibertyProvider.DoesNotExist: |
112 |
self.logger.error(u'session found for unknown provider %s', provider_id)
|
|
112 |
self.logger.error('session found for unknown provider %s', provider_id) |
|
113 | 113 |
else: |
114 | 114 |
policy = common.get_sp_options_policy(provider) |
115 | 115 |
if not policy: |
116 |
self.logger.error(u'No policy found for %s', provider_id)
|
|
116 |
self.logger.error('No policy found for %s', provider_id) |
|
117 | 117 |
elif not policy.forward_slo: |
118 |
self.logger.info(u'%s configured to not reveive slo', provider_id)
|
|
118 |
self.logger.info('%s configured to not reveive slo', provider_id) |
|
119 | 119 |
else: |
120 | 120 |
url = reverse(saml2_endpoints.idp_slo, args=[provider_id]) |
121 | 121 |
# add a nonce so this link is never cached |
122 | 122 |
nonce = hex(random.getrandbits(128)) |
123 |
url = '{0}?provider_id={1}&nonce={2}'.format(url, quote(provider_id), nonce)
|
|
123 |
url = f'{url}?provider_id={quote(provider_id)}&nonce={nonce}'
|
|
124 | 124 |
name = name or provider_id |
125 | 125 |
code = render_to_string( |
126 | 126 |
'idp/saml/logout_fragment.html', |
src/authentic2/idp/saml/saml2_endpoints.py | ||
---|---|---|
32 | 32 |
- assertionIDRequest |
33 | 33 |
""" |
34 | 34 | |
35 |
from __future__ import unicode_literals |
|
36 | 35 | |
37 | 36 |
import datetime |
38 | 37 |
import hashlib |
39 | 38 |
import logging |
40 | 39 |
import random |
41 | 40 |
import string |
42 |
import xml.etree.cElementTree as ctree
|
|
41 |
import xml.etree.ElementTree as ctree |
|
43 | 42 |
from functools import wraps |
44 | 43 |
from urllib.parse import quote, urlencode |
45 | 44 | |
... | ... | |
367 | 366 |
if attributes: |
368 | 367 |
logger.debug('adding attributes') |
369 | 368 |
logger.debug('assertion before processing %s', force_text(assertion.dump())) |
370 |
logger.debug(u'adding attributes %s', attributes)
|
|
369 |
logger.debug('adding attributes %s', attributes) |
|
371 | 370 |
if not assertion.attributeStatement: |
372 | 371 |
assertion.attributeStatement = [lasso.Saml2AttributeStatement()] |
373 | 372 |
attribute_statement = assertion.attributeStatement[0] |
... | ... | |
429 | 428 |
else: |
430 | 429 |
try: |
431 | 430 |
event = find_authentication_event(request, login.request.id) |
432 |
logger.debug(u'authentication from stored event %s', event)
|
|
431 |
logger.debug('authentication from stored event %s', event) |
|
433 | 432 |
how = event['how'] |
434 | 433 |
if how == 'password': |
435 | 434 |
authn_context = lasso.SAML2_AUTHN_CONTEXT_PASSWORD |
... | ... | |
506 | 505 |
logger.debug('called by GET') |
507 | 506 |
consent_answer = request.GET.get('consent_answer', '') |
508 | 507 |
if consent_answer: |
509 |
logger.debug(u'back from the consent page for federation with answer %s', consent_answer)
|
|
508 |
logger.debug('back from the consent page for federation with answer %s', consent_answer) |
|
510 | 509 |
server = create_server(request) |
511 | 510 |
login = lasso.Login(server) |
512 | 511 |
message = get_saml2_request_message(request, login) |
... | ... | |
673 | 672 |
logger.debug('back from the consent page for federation with answer %s', consent_answer) |
674 | 673 |
consent_attribute_answer = request.GET.get('consent_attribute_answer', '') |
675 | 674 |
if consent_attribute_answer: |
676 |
logger.debug(u'back from the consent page for attributes %s', consent_attribute_answer)
|
|
675 |
logger.debug('back from the consent page for attributes %s', consent_attribute_answer) |
|
677 | 676 |
nonce = request.GET.get(NONCE_FIELD_NAME, '') |
678 | 677 |
if not nonce: |
679 | 678 |
logger.warning('nonce not found') |
... | ... | |
806 | 805 |
if dic and 'authz' in dic: |
807 | 806 |
logger.debug('decision is %s', dic['authz']) |
808 | 807 |
if 'message' in dic: |
809 |
logger.debug(u'with message %s', dic['message'])
|
|
808 |
logger.debug('with message %s', dic['message']) |
|
810 | 809 |
if not dic['authz']: |
811 | 810 |
logger.debug('access denied by an external function') |
812 | 811 |
access_granted = False |
... | ... | |
932 | 931 | |
933 | 932 |
name_id = build_assertion(request, login, provider, nid_format=nid_format) |
934 | 933 |
hooks.call_hooks('event', name='sso-success', idp='saml2', service=service, user=request.user) |
935 |
logger.info(u'sso success sending AuthenticationResponse to %s with NameID %s', service, name_id)
|
|
934 |
logger.info('sso success sending AuthenticationResponse to %s with NameID %s', service, name_id) |
|
936 | 935 |
return finish_sso(request, login, user=user, return_profile=return_profile) |
937 | 936 | |
938 | 937 | |
... | ... | |
1211 | 1210 |
) |
1212 | 1211 |
django_session_keys = [s.django_session_key for s in lib_session1] |
1213 | 1212 |
lib_session = LibertySession.objects.filter(django_session_key__in=django_session_keys) |
1214 |
providers = set([s.provider_id for s in lib_session])
|
|
1213 |
providers = {s.provider_id for s in lib_session}
|
|
1215 | 1214 |
result = [] |
1216 | 1215 |
for provider in providers: |
1217 | 1216 |
if provider != provider_id: |
... | ... | |
1236 | 1235 |
'AssertionID="xxx" ' |
1237 | 1236 |
'SessionIndex="{0.session_index}">'.format(liberty_session) |
1238 | 1237 |
) |
1239 |
session.append(u'<saml:NameID Format="{0.name_id_format}" '.format(liberty_session))
|
|
1238 |
session.append(f'<saml:NameID Format="{liberty_session.name_id_format}" ')
|
|
1240 | 1239 |
if liberty_session.name_id_qualifier: |
1241 |
session.append(u'NameQualifier="{0.name_id_qualifier}" '.format(liberty_session))
|
|
1240 |
session.append(f'NameQualifier="{liberty_session.name_id_qualifier}" ')
|
|
1242 | 1241 |
if liberty_session.name_id_sp_name_qualifier: |
1243 |
session.append(u'SPNameQualifier="{0.name_id_sp_name_qualifier}" '.format(liberty_session))
|
|
1244 |
session.append(u'>{0.name_id_content}</saml:NameID>'.format(liberty_session))
|
|
1245 |
session.append(u'</NidAndSessionIndex>')
|
|
1246 |
session.append(u'</Session>')
|
|
1242 |
session.append(f'SPNameQualifier="{liberty_session.name_id_sp_name_qualifier}" ')
|
|
1243 |
session.append(f'>{liberty_session.name_id_content}</saml:NameID>')
|
|
1244 |
session.append('</NidAndSessionIndex>') |
|
1245 |
session.append('</Session>') |
|
1247 | 1246 |
s = ''.join(session) |
1248 | 1247 |
logger.debug('session built %s', s) |
1249 | 1248 |
return s |
... | ... | |
1302 | 1301 |
logger.debug('slo cannot logout provider %s, it is no more known.', lib_session.provider_id) |
1303 | 1302 |
continue |
1304 | 1303 |
else: |
1305 |
logger.debug(u'provider %s loaded', p)
|
|
1304 |
logger.debug('provider %s loaded', p) |
|
1306 | 1305 |
policy = get_sp_options_policy(p) |
1307 | 1306 |
if not policy: |
1308 | 1307 |
logger.warning('No policy found for %s', lib_session.provider_id) |
src/authentic2/idp/saml/views.py | ||
---|---|---|
33 | 33 | |
34 | 34 |
def get_queryset(self): |
35 | 35 |
# check current user owns this federation |
36 |
qs = super(FederationDeleteView, self).get_queryset()
|
|
36 |
qs = super().get_queryset() |
|
37 | 37 |
return qs.filter(user=self.request.user) |
38 | 38 | |
39 | 39 |
def delete(self, request, *args, **kwargs): |
src/authentic2/ldap_utils.py | ||
---|---|---|
24 | 24 | |
25 | 25 |
class DnFormatter(string.Formatter): |
26 | 26 |
def get_value(self, key, args, kwargs): |
27 |
value = super(DnFormatter, self).get_value(key, args, kwargs)
|
|
27 |
value = super().get_value(key, args, kwargs) |
|
28 | 28 |
return value |
29 | 29 | |
30 | 30 |
def get_field(self, field_name, args, kwargs): |
31 |
value, used_arg = super(DnFormatter, self).get_field(field_name, args, kwargs)
|
|
31 |
value, used_arg = super().get_field(field_name, args, kwargs) |
|
32 | 32 |
if isinstance(value, (list, tuple)) and len(value) == 1: |
33 | 33 |
value = value[0] |
34 | 34 |
return value, used_arg |
35 | 35 | |
36 | 36 |
def format_field(self, value, format_spec): |
37 |
value = super(DnFormatter, self).format_field(value, format_spec)
|
|
37 |
value = super().format_field(value, format_spec) |
|
38 | 38 |
return ldap.dn.escape_dn_chars(value) |
39 | 39 | |
40 | 40 |
def convert_field(self, value, conversion): |
41 | 41 |
if conversion == 's': |
42 | 42 |
return force_text(value) |
43 |
return super(DnFormatter, self).convert_field(value, conversion)
|
|
43 |
return super().convert_field(value, conversion) |
|
44 | 44 | |
45 | 45 | |
46 | 46 |
class FilterFormatter(string.Formatter): |
47 | 47 |
def get_value(self, key, args, kwargs): |
48 |
value = super(FilterFormatter, self).get_value(key, args, kwargs)
|
|
48 |
value = super().get_value(key, args, kwargs) |
|
49 | 49 |
return value |
50 | 50 | |
51 | 51 |
def get_field(self, field_name, args, kwargs): |
52 |
value, used_arg = super(FilterFormatter, self).get_field(field_name, args, kwargs)
|
|
52 |
value, used_arg = super().get_field(field_name, args, kwargs) |
|
53 | 53 |
if isinstance(value, (list, tuple)) and len(value) == 1: |
54 | 54 |
value = value[0] |
55 | 55 |
return value, used_arg |
56 | 56 | |
57 | 57 |
def format_field(self, value, format_spec): |
58 |
value = super(FilterFormatter, self).format_field(value, format_spec)
|
|
58 |
value = super().format_field(value, format_spec) |
|
59 | 59 |
return ldap.filter.escape_filter_chars(value) |
60 | 60 | |
61 | 61 |
def convert_field(self, value, conversion): |
62 | 62 |
if conversion == 's': |
63 | 63 |
return force_text(value) |
64 |
return super(FilterFormatter, self).convert_field(value, conversion) |
|
64 |
return super().convert_field(value, conversion) |
src/authentic2/logger.py | ||
---|---|---|
19 | 19 | |
20 | 20 |
class SettingsLogLevel(int): |
21 | 21 |
def __new__(cls, default_log_level, debug_setting='DEBUG'): |
22 |
return super(SettingsLogLevel, cls).__new__(cls, getattr(logging, default_log_level))
|
|
22 |
return super().__new__(cls, getattr(logging, default_log_level)) |
|
23 | 23 | |
24 | 24 |
def __init__(self, default_log_level, debug_setting='DEBUG'): |
25 | 25 |
self.debug_setting = debug_setting |
26 |
super(SettingsLogLevel, self).__init__()
|
|
26 |
super().__init__() |
|
27 | 27 | |
28 | 28 | |
29 | 29 |
class DjangoLogger(logging.getLoggerClass()): |
30 | 30 |
def getEffectiveLevel(self): |
31 |
level = super(DjangoLogger, self).getEffectiveLevel()
|
|
31 |
level = super().getEffectiveLevel() |
|
32 | 32 |
if isinstance(level, SettingsLogLevel): |
33 | 33 |
from django.conf import settings |
34 | 34 |
src/authentic2/management/commands/check-and-repair.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import unicode_literals |
|
18 | 17 | |
19 | 18 |
import contextlib |
20 | 19 |
import traceback |
... | ... | |
47 | 46 |
from tenant_schemas.utils import tenant_context |
48 | 47 | |
49 | 48 | |
50 |
class FakeState(object):
|
|
49 |
class FakeState: |
|
51 | 50 |
class FakeException(Exception): |
52 | 51 |
pass |
53 | 52 | |
... | ... | |
369 | 368 |
to_change_ou = [] |
370 | 369 |
with fake_atomic() as fake_state: |
371 | 370 |
admin_role = role.get_admin_role() |
372 |
ok = set(manager_roles) <= set([admin_role])
|
|
371 |
ok = set(manager_roles) <= {admin_role}
|
|
373 | 372 |
if ok and manager_roles: |
374 | 373 |
if list(manager_roles)[0].ou != role.ou: |
375 | 374 |
self.warning( |
src/authentic2/management/commands/clean-unused-accounts.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import print_function |
|
18 | 17 | |
19 | 18 |
import logging |
20 | 19 |
import urllib.parse |
src/authentic2/management/commands/import_site.py | ||
---|---|---|
69 | 69 |
msg = "Dry run\n" if dry_run else "Real run\n" |
70 | 70 |
c_kwargs = create_context_args(options) |
71 | 71 |
try: |
72 |
with open(filename, 'r') as f:
|
|
72 |
with open(filename) as f: |
|
73 | 73 |
with transaction.atomic(): |
74 | 74 |
sys.stdout.write(msg) |
75 | 75 |
result = import_site(json.load(f), ImportContext(**c_kwargs)) |
src/authentic2/management/commands/slapd-shell.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import print_function |
|
18 | 17 | |
19 | 18 |
import io |
20 | 19 |
import logging |
... | ... | |
88 | 87 |
o[ldap_attribute] = [str(getattr(user, user_attribute)).encode('utf-8')] |
89 | 88 |
o['objectClass'] = ['inetOrgPerson'] |
90 | 89 |
dn = 'uid=%s,%s' % (escape_dn_chars(o['uid'][0]), attrs['suffix']) |
91 |
self.logger.debug(u'sending entry %s %s', dn, o)
|
|
90 |
self.logger.debug('sending entry %s %s', dn, o) |
|
92 | 91 |
ldif_writer.unparse(dn, o) |
93 | 92 |
print(out.getvalue()) |
94 | 93 |
out.close() |
src/authentic2/management/commands/sync-ldap-users.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import print_function |
|
18 | 17 | |
19 | 18 |
try: |
20 | 19 |
import ldap |
src/authentic2/manager/app_settings.py | ||
---|---|---|
17 | 17 |
import sys |
18 | 18 | |
19 | 19 | |
20 |
class AppSettings(object):
|
|
20 |
class AppSettings: |
|
21 | 21 |
__PREFIX = 'A2_MANAGER_' |
22 | 22 |
__DEFAULTS = { |
23 | 23 |
'HOMEPAGE_URL': None, |
src/authentic2/manager/fields.py | ||
---|---|---|
19 | 19 |
from . import widgets |
20 | 20 | |
21 | 21 | |
22 |
class Select2Mixin(object):
|
|
22 |
class Select2Mixin: |
|
23 | 23 |
def __init__(self, **kwargs): |
24 | 24 |
kwargs['queryset'] = self.widget.get_initial_queryset() |
25 |
super(Select2Mixin, self).__init__(**kwargs)
|
|
25 |
super().__init__(**kwargs) |
|
26 | 26 | |
27 | 27 |
def __setattr__(self, key, value): |
28 | 28 |
if key == 'queryset': |
29 | 29 |
self.widget.queryset = value |
30 |
super(Select2Mixin, self).__setattr__(key, value)
|
|
30 |
super().__setattr__(key, value) |
|
31 | 31 | |
32 | 32 | |
33 | 33 |
class Select2ModelChoiceField(Select2Mixin, forms.ModelChoiceField): |
src/authentic2/manager/forms.py | ||
---|---|---|
54 | 54 |
logger = logging.getLogger(__name__) |
55 | 55 | |
56 | 56 | |
57 |
class CssClass(object):
|
|
57 |
class CssClass: |
|
58 | 58 |
pass |
59 | 59 | |
60 | 60 | |
... | ... | |
63 | 63 | |
64 | 64 |
def __init__(self, *args, **kwargs): |
65 | 65 |
self.request = kwargs.pop('request') |
66 |
super(FormWithRequest, self).__init__(*args, **kwargs)
|
|
66 |
super().__init__(*args, **kwargs) |
|
67 | 67 | |
68 | 68 | |
69 | 69 |
class SlugMixin(forms.ModelForm): |
... | ... | |
80 | 80 |
i += 1 |
81 | 81 |
if len(instance.slug) > 256: |
82 | 82 |
instance.slug = instance.slug[:252] + hashlib.md5(instance.slug).hexdigest()[:4] |
83 |
return super(SlugMixin, self).save(commit=commit)
|
|
83 |
return super().save(commit=commit) |
|
84 | 84 | |
85 | 85 | |
86 |
class PrefixFormMixin(object):
|
|
86 |
class PrefixFormMixin: |
|
87 | 87 |
def __init__(self, *args, **kwargs): |
88 | 88 |
kwargs['prefix'] = self.__class__.prefix |
89 |
super(PrefixFormMixin, self).__init__(*args, **kwargs)
|
|
89 |
super().__init__(*args, **kwargs) |
|
90 | 90 | |
91 | 91 | |
92 | 92 |
class LimitQuerysetFormMixin(FormWithRequest): |
... | ... | |
95 | 95 |
""" |
96 | 96 | |
97 | 97 |
def __init__(self, *args, **kwargs): |
98 |
super(LimitQuerysetFormMixin, self).__init__(*args, **kwargs)
|
|
98 |
super().__init__(*args, **kwargs) |
|
99 | 99 |
if self.request and not self.request.user.is_anonymous: |
100 | 100 |
for name, field in self.fields.items(): |
101 | 101 |
qs = getattr(field, 'queryset', None) |
... | ... | |
115 | 115 | |
116 | 116 |
def __init__(self, *args, **kwargs): |
117 | 117 |
ou = kwargs.pop('ou', None) |
118 |
super(ChooseUserForm, self).__init__(*args, **kwargs)
|
|
118 |
super().__init__(*args, **kwargs) |
|
119 | 119 |
# Filter user by ou if asked |
120 | 120 |
if ou: |
121 | 121 |
self.fields['user'].queryset = self.fields['user'].queryset.filter(ou=ou) |
... | ... | |
147 | 147 | |
148 | 148 |
def __init__(self, *args, **kwargs): |
149 | 149 |
ou = kwargs.pop('ou', None) |
150 |
super(ChooseUserRoleForm, self).__init__(*args, **kwargs)
|
|
150 |
super().__init__(*args, **kwargs) |
|
151 | 151 |
# Filter roles by ou if asked |
152 | 152 |
if ou: |
153 | 153 |
self.fields['role'].queryset = self.fields['role'].queryset.filter(ou=ou) |
... | ... | |
176 | 176 |
def __init__(self, *args, **kwargs): |
177 | 177 |
request = kwargs.get('request') |
178 | 178 | |
179 |
super(UserEditForm, self).__init__(*args, **kwargs)
|
|
179 |
super().__init__(*args, **kwargs) |
|
180 | 180 |
if 'ou' in self.fields and not request.user.is_superuser: |
181 | 181 |
field = self.fields['ou'] |
182 | 182 |
field.required = True |
... | ... | |
220 | 220 |
return password2 |
221 | 221 | |
222 | 222 |
def clean(self): |
223 |
super(UserChangePasswordForm, self).clean()
|
|
223 |
super().clean() |
|
224 | 224 |
if ( |
225 | 225 |
self.require_password |
226 | 226 |
and not self.cleaned_data.get('generate_password') |
... | ... | |
243 | 243 |
return bool(self.instance and self.instance.email) |
244 | 244 | |
245 | 245 |
def save(self, commit=True): |
246 |
user = super(UserChangePasswordForm, self).save(commit=False)
|
|
246 |
user = super().save(commit=False) |
|
247 | 247 |
new_password = None |
248 | 248 |
if self.cleaned_data.get('generate_password'): |
249 | 249 |
new_password = generate_password() |
... | ... | |
294 | 294 | |
295 | 295 |
def __init__(self, *args, **kwargs): |
296 | 296 |
self.ou = kwargs.pop('ou', None) |
297 |
super(UserAddForm, self).__init__(*args, **kwargs)
|
|
297 |
super().__init__(*args, **kwargs) |
|
298 | 298 | |
299 | 299 |
def clean(self): |
300 | 300 |
self.instance.ou = self.ou |
301 |
super(UserAddForm, self).clean()
|
|
301 |
super().clean() |
|
302 | 302 |
# check if this account is going to be real online account, i.e. with a |
303 | 303 |
# password, it it's the case complain that there is no identifiers. |
304 | 304 |
has_password = ( |
... | ... | |
319 | 319 |
return bool(self.cleaned_data.get('email')) |
320 | 320 | |
321 | 321 |
def save(self, commit=True): |
322 |
user = super(UserAddForm, self).save(commit=commit)
|
|
322 |
user = super().save(commit=commit) |
|
323 | 323 |
if self.cleaned_data.get('reset_password_at_next_login'): |
324 | 324 |
if commit: |
325 | 325 |
PasswordReset.objects.get_or_create(user=user) |
... | ... | |
364 | 364 |
internals = forms.BooleanField(initial=False, label=_('Show internal roles'), required=False) |
365 | 365 | |
366 | 366 |
def __init__(self, *args, **kwargs): |
367 |
super(ServiceRoleSearchForm, self).__init__(*args, **kwargs)
|
|
367 |
super().__init__(*args, **kwargs) |
|
368 | 368 |
if app_settings.SHOW_INTERNAL_ROLES: |
369 | 369 |
del self.fields['internals'] |
370 | 370 | |
371 | 371 |
def filter(self, qs): |
372 |
if hasattr(super(ServiceRoleSearchForm, self), 'filter'):
|
|
373 |
qs = super(ServiceRoleSearchForm, self).filter(qs)
|
|
372 |
if hasattr(super(), 'filter'): |
|
373 |
qs = super().filter(qs) |
|
374 | 374 |
if self.cleaned_data.get('text'): |
375 | 375 |
qs = qs.filter(name__icontains=self.cleaned_data['text']) |
376 | 376 |
if not app_settings.SHOW_INTERNAL_ROLES and not self.cleaned_data.get('internals'): |
... | ... | |
378 | 378 |
return qs |
379 | 379 | |
380 | 380 | |
381 |
class HideOUFieldMixin(object):
|
|
381 |
class HideOUFieldMixin: |
|
382 | 382 |
def __init__(self, *args, **kwargs): |
383 |
super(HideOUFieldMixin, self).__init__(*args, **kwargs)
|
|
383 |
super().__init__(*args, **kwargs) |
|
384 | 384 |
if utils.get_ou_count() < 2: |
385 | 385 |
del self.fields['ou'] |
386 | 386 | |
387 | 387 |
def clean(self): |
388 | 388 |
if 'ou' not in self.fields: |
389 | 389 |
self.instance.ou = get_default_ou() |
390 |
return super(HideOUFieldMixin, self).clean()
|
|
390 |
return super().clean() |
|
391 | 391 | |
392 | 392 | |
393 | 393 |
class OUSearchForm(FormWithRequest): |
... | ... | |
464 | 464 |
else: |
465 | 465 |
data[ou_key] = str(self.ou_qs[0].pk) |
466 | 466 | |
467 |
super(OUSearchForm, self).__init__(*args, **kwargs)
|
|
467 |
super().__init__(*args, **kwargs) |
|
468 | 468 | |
469 | 469 |
# modify choices after initialization |
470 | 470 |
if self.ou_count > 1: |
... | ... | |
519 | 519 |
return qs |
520 | 520 | |
521 | 521 |
def filter(self, qs): |
522 |
if hasattr(super(OUSearchForm, self), 'filter'):
|
|
523 |
qs = super(OUSearchForm, self).filter(qs)
|
|
522 |
if hasattr(super(), 'filter'): |
|
523 |
qs = super().filter(qs) |
|
524 | 524 |
qs = self.filter_by_ou(qs) |
525 | 525 |
return qs |
526 | 526 | |
... | ... | |
546 | 546 |
else: |
547 | 547 |
ou_qs = ou_qs.none() |
548 | 548 |
kwargs['ou_queryset'] = ou_qs |
549 |
super(UserRoleSearchForm, self).__init__(*args, **kwargs)
|
|
549 |
super().__init__(*args, **kwargs) |
|
550 | 550 | |
551 | 551 |
def filter_no_ou(self, qs): |
552 | 552 |
return qs |
... | ... | |
560 | 560 | |
561 | 561 |
def __init__(self, *args, **kwargs): |
562 | 562 |
self.minimum_chars = kwargs.pop('minimum_chars', 0) |
563 |
super(UserSearchForm, self).__init__(*args, **kwargs)
|
|
563 |
super().__init__(*args, **kwargs) |
|
564 | 564 | |
565 | 565 |
def not_enough_chars(self): |
566 | 566 |
text = self.cleaned_data.get('text') |
... | ... | |
571 | 571 |
return text and len(text) >= self.minimum_chars |
572 | 572 | |
573 | 573 |
def filter(self, qs): |
574 |
qs = super(UserSearchForm, self).filter(qs)
|
|
574 |
qs = super().filter(qs) |
|
575 | 575 |
if self.enough_chars(): |
576 | 576 |
qs = qs.free_text_search(self.cleaned_data['text']) |
577 | 577 |
elif self.not_enough_chars(): |
... | ... | |
610 | 610 | |
611 | 611 |
class OUEditForm(SlugMixin, CssClass, forms.ModelForm): |
612 | 612 |
def __init__(self, *args, **kwargs): |
613 |
super(OUEditForm, self).__init__(*args, **kwargs)
|
|
613 |
super().__init__(*args, **kwargs) |
|
614 | 614 |
self.fields['name'].label = _('label').title() |
615 | 615 | |
616 | 616 |
class Meta: |
... | ... | |
646 | 646 |
instance = kwargs.get('instance') |
647 | 647 |
if instance: |
648 | 648 |
initial['new_email'] = instance.email |
649 |
super(UserChangeEmailForm, self).__init__(*args, **kwargs)
|
|
649 |
super().__init__(*args, **kwargs) |
|
650 | 650 | |
651 | 651 |
def save(self, *args, **kwargs): |
652 | 652 |
new_email = self.cleaned_data['new_email'] |
src/authentic2/manager/ou_views.py | ||
---|---|---|
70 | 70 |
return str(self.object) |
71 | 71 | |
72 | 72 |
def authorize(self, request, *args, **kwargs): |
73 |
super(OrganizationalUnitDetailView, self).authorize(request, *args, **kwargs)
|
|
73 |
super().authorize(request, *args, **kwargs) |
|
74 | 74 |
self.can_delete = self.can_delete and not self.object.default |
75 | 75 | |
76 | 76 | |
... | ... | |
106 | 106 |
), |
107 | 107 |
) |
108 | 108 |
return self.return_ajax_response(request, HttpResponseRedirect(self.get_success_url())) |
109 |
return super(OrganizationalUnitDeleteView, self).dispatch(request, *args, **kwargs)
|
|
109 |
return super().dispatch(request, *args, **kwargs) |
|
110 | 110 | |
111 | 111 | |
112 | 112 |
delete = OrganizationalUnitDeleteView.as_view() |
src/authentic2/manager/role_views.py | ||
---|---|---|
43 | 43 |
OU = get_ou_model() |
44 | 44 | |
45 | 45 | |
46 |
class RolesMixin(object):
|
|
46 |
class RolesMixin: |
|
47 | 47 |
service_roles = True |
48 | 48 |
admin_roles = False |
49 | 49 | |
50 | 50 |
def get_queryset(self): |
51 |
qs = super(RolesMixin, self).get_queryset()
|
|
51 |
qs = super().get_queryset() |
|
52 | 52 |
qs = qs.select_related('ou') |
53 | 53 |
Permission = get_permission_model() |
54 | 54 |
permission_ct = ContentType.objects.get_for_model(Permission) |
... | ... | |
78 | 78 |
title = _('Roles') |
79 | 79 | |
80 | 80 |
def get_queryset(self): |
81 |
qs = super(RolesView, self).get_queryset()
|
|
81 |
qs = super().get_queryset() |
|
82 | 82 |
qs = qs.annotate(member_count=Count('members')) |
83 | 83 |
return qs |
84 | 84 | |
85 | 85 |
def get_search_form_kwargs(self): |
86 |
kwargs = super(RolesView, self).get_search_form_kwargs()
|
|
86 |
kwargs = super().get_search_form_kwargs() |
|
87 | 87 |
kwargs['queryset'] = self.get_queryset() |
88 | 88 |
return kwargs |
89 | 89 | |
... | ... | |
111 | 111 |
return modelform_factory(self.model, form=form, fields=fields) |
112 | 112 | |
113 | 113 |
def form_valid(self, form): |
114 |
response = super(RoleAddView, self).form_valid(form)
|
|
114 |
response = super().form_valid(form) |
|
115 | 115 |
hooks.call_hooks( |
116 | 116 |
'event', name='manager-add-role', user=self.request.user, instance=form.instance, form=form |
117 | 117 |
) |
... | ... | |
135 | 135 |
) |
136 | 136 |
) |
137 | 137 |
return self.export_response(json.dumps(export, indent=4), 'application/json', 'json') |
138 |
return super(RolesExportView, self).get(request, *args, **kwargs)
|
|
138 |
return super().get(request, *args, **kwargs) |
|
139 | 139 | |
140 | 140 | |
141 | 141 |
export = RolesExportView.as_view() |
... | ... | |
158 | 158 |
return forms.get_role_form_class() |
159 | 159 | |
160 | 160 |
def form_valid(self, form): |
161 |
response = super(RoleEditView, self).form_valid(form)
|
|
161 |
response = super().form_valid(form) |
|
162 | 162 |
hooks.call_hooks( |
163 | 163 |
'event', name='manager-edit-role', user=self.request.user, instance=form.instance, form=form |
164 | 164 |
) |
... | ... | |
230 | 230 |
) |
231 | 231 |
else: |
232 | 232 |
messages.warning(self.request, _('You are not authorized')) |
233 |
return super(RoleMembersView, self).form_valid(form)
|
|
233 |
return super().form_valid(form) |
|
234 | 234 | |
235 | 235 |
def get_form_kwargs(self): |
236 |
kwargs = super(RoleMembersView, self).get_form_kwargs()
|
|
236 |
kwargs = super().get_form_kwargs() |
|
237 | 237 |
# if role's members can only be from the same OU we filter user based on the role's OU |
238 | 238 |
if app_settings.ROLE_MEMBERS_FROM_OU: |
239 | 239 |
kwargs['ou'] = self.object.ou |
240 | 240 |
return kwargs |
241 | 241 | |
242 | 242 |
def get_context_data(self, **kwargs): |
243 |
ctx = super(RoleMembersView, self).get_context_data(**kwargs)
|
|
243 |
ctx = super().get_context_data(**kwargs) |
|
244 | 244 |
ctx['children'] = views.filter_view( |
245 | 245 |
self.request, self.object.children(include_self=False, annotate=True) |
246 | 246 |
) |
... | ... | |
281 | 281 |
def post(self, request, *args, **kwargs): |
282 | 282 |
if not self.can_delete: |
283 | 283 |
raise PermissionDenied |
284 |
return super(RoleDeleteView, self).post(request, *args, **kwargs)
|
|
284 |
return super().post(request, *args, **kwargs) |
|
285 | 285 | |
286 | 286 |
def get_success_url(self): |
287 | 287 |
return reverse('a2-manager-roles') |
... | ... | |
291 | 291 | |
292 | 292 |
hooks.call_hooks('event', name='manager-delete-role', user=request.user, role=role) |
293 | 293 |
self.request.journal.record('manager.role.deletion', role=role) |
294 |
return super(RoleDeleteView, self).delete(request, *args, **kwargs)
|
|
294 |
return super().delete(request, *args, **kwargs) |
|
295 | 295 | |
296 | 296 | |
297 | 297 |
delete = RoleDeleteView.as_view() |
... | ... | |
348 | 348 |
) |
349 | 349 |
else: |
350 | 350 |
messages.warning(self.request, _('You are not authorized')) |
351 |
return super(RolePermissionsView, self).form_valid(form)
|
|
351 |
return super().form_valid(form) |
|
352 | 352 | |
353 | 353 | |
354 | 354 |
permissions = RolePermissionsView.as_view() |
... | ... | |
382 | 382 | |
383 | 383 |
def dispatch(self, request, *args, **kwargs): |
384 | 384 |
self.object = self.get_object() |
385 |
return super(RoleAddChildView, self).dispatch(request, *args, **kwargs)
|
|
385 |
return super().dispatch(request, *args, **kwargs) |
|
386 | 386 | |
387 | 387 |
def form_valid(self, form): |
388 | 388 |
parent = self.get_object() |
... | ... | |
392 | 392 |
'event', name='manager-add-child-role', user=self.request.user, parent=parent, child=role |
393 | 393 |
) |
394 | 394 |
self.request.journal.record('manager.role.inheritance.addition', parent=parent, child=role) |
395 |
return super(RoleAddChildView, self).form_valid(form)
|
|
395 |
return super().form_valid(form) |
|
396 | 396 | |
397 | 397 | |
398 | 398 |
add_child = RoleAddChildView.as_view() |
... | ... | |
411 | 411 |
self.object = self.get_object() |
412 | 412 |
if self.object.is_internal(): |
413 | 413 |
raise PermissionDenied |
414 |
return super(RoleAddParentView, self).dispatch(request, *args, **kwargs)
|
|
414 |
return super().dispatch(request, *args, **kwargs) |
|
415 | 415 | |
416 | 416 |
def form_valid(self, form): |
417 | 417 |
child = self.get_object() |
... | ... | |
421 | 421 |
'event', name='manager-add-child-role', user=self.request.user, parent=role, child=child |
422 | 422 |
) |
423 | 423 |
self.request.journal.record('manager.role.inheritance.addition', parent=role, child=child) |
424 |
return super(RoleAddParentView, self).form_valid(form)
|
|
424 |
return super().form_valid(form) |
|
425 | 425 | |
426 | 426 | |
427 | 427 |
add_parent = RoleAddParentView.as_view() |
... | ... | |
437 | 437 |
def dispatch(self, request, *args, **kwargs): |
438 | 438 |
self.object = self.get_object() |
439 | 439 |
self.child = self.get_queryset().get(pk=kwargs['child_pk']) |
440 |
return super(RoleRemoveChildView, self).dispatch(request, *args, **kwargs)
|
|
440 |
return super().dispatch(request, *args, **kwargs) |
|
441 | 441 | |
442 | 442 |
def get_context_data(self, **kwargs): |
443 |
ctx = super(RoleRemoveChildView, self).get_context_data(**kwargs)
|
|
443 |
ctx = super().get_context_data(**kwargs) |
|
444 | 444 |
ctx['child'] = self.child |
445 | 445 |
return ctx |
446 | 446 | |
... | ... | |
471 | 471 |
if self.object.is_internal(): |
472 | 472 |
raise PermissionDenied |
473 | 473 |
self.parent = self.get_queryset().get(pk=kwargs['parent_pk']) |
474 |
return super(RoleRemoveParentView, self).dispatch(request, *args, **kwargs)
|
|
474 |
return super().dispatch(request, *args, **kwargs) |
|
475 | 475 | |
476 | 476 |
def get_context_data(self, **kwargs): |
477 |
ctx = super(RoleRemoveParentView, self).get_context_data(**kwargs)
|
|
477 |
ctx = super().get_context_data(**kwargs) |
|
478 | 478 |
ctx['parent'] = self.parent |
479 | 479 |
return ctx |
480 | 480 | |
... | ... | |
513 | 513 | |
514 | 514 |
def dispatch(self, request, *args, **kwargs): |
515 | 515 |
self.object = self.get_object() |
516 |
return super(RoleAddAdminRoleView, self).dispatch(request, *args, **kwargs)
|
|
516 |
return super().dispatch(request, *args, **kwargs) |
|
517 | 517 | |
518 | 518 |
def form_valid(self, form): |
519 | 519 |
administered_role = self.get_object() |
... | ... | |
529 | 529 |
self.request.journal.record( |
530 | 530 |
'manager.role.administrator.role.addition', role=administered_role, admin_role=role |
531 | 531 |
) |
532 |
return super(RoleAddAdminRoleView, self).form_valid(form)
|
|
532 |
return super().form_valid(form) |
|
533 | 533 | |
534 | 534 | |
535 | 535 |
add_admin_role = RoleAddAdminRoleView.as_view() |
... | ... | |
547 | 547 |
def dispatch(self, request, *args, **kwargs): |
548 | 548 |
self.object = self.get_object() |
549 | 549 |
self.child = self.get_queryset().get(pk=kwargs['role_pk']) |
550 |
return super(RoleRemoveAdminRoleView, self).dispatch(request, *args, **kwargs)
|
|
550 |
return super().dispatch(request, *args, **kwargs) |
|
551 | 551 | |
552 | 552 |
def get_context_data(self, **kwargs): |
553 |
ctx = super(RoleRemoveAdminRoleView, self).get_context_data(**kwargs)
|
|
553 |
ctx = super().get_context_data(**kwargs) |
|
554 | 554 |
ctx['child'] = self.child |
555 | 555 |
return ctx |
556 | 556 | |
... | ... | |
589 | 589 | |
590 | 590 |
def dispatch(self, request, *args, **kwargs): |
591 | 591 |
self.object = self.get_object() |
592 |
return super(RoleAddAdminUserView, self).dispatch(request, *args, **kwargs)
|
|
592 |
return super().dispatch(request, *args, **kwargs) |
|
593 | 593 | |
594 | 594 |
def form_valid(self, form): |
595 | 595 |
administered_role = self.get_object() |
... | ... | |
605 | 605 |
self.request.journal.record( |
606 | 606 |
'manager.role.administrator.user.addition', role=administered_role, admin_user=user |
607 | 607 |
) |
608 |
return super(RoleAddAdminUserView, self).form_valid(form)
|
|
608 |
return super().form_valid(form) |
|
609 | 609 | |
610 | 610 | |
611 | 611 |
add_admin_user = RoleAddAdminUserView.as_view() |
... | ... | |
623 | 623 |
def dispatch(self, request, *args, **kwargs): |
624 | 624 |
self.object = self.get_object() |
625 | 625 |
self.user = get_user_model().objects.get(pk=kwargs['user_pk']) |
626 |
return super(RoleRemoveAdminUserView, self).dispatch(request, *args, **kwargs)
|
|
626 |
return super().dispatch(request, *args, **kwargs) |
|
627 | 627 | |
628 | 628 |
def get_context_data(self, **kwargs): |
629 |
ctx = super(RoleRemoveAdminUserView, self).get_context_data(**kwargs)
|
|
629 |
ctx = super().get_context_data(**kwargs) |
|
630 | 630 |
ctx['user'] = self.user |
631 | 631 |
return ctx |
632 | 632 |
src/authentic2/manager/service_views.py | ||
---|---|---|
63 | 63 |
return self.object.authorized_roles.all() |
64 | 64 | |
65 | 65 |
def get(self, request, *args, **kwargs): |
66 |
result = super(ServiceView, self).get(request, *args, **kwargs)
|
|
66 |
result = super().get(request, *args, **kwargs) |
|
67 | 67 |
self.service = self.object |
68 | 68 |
return result |
69 | 69 | |
... | ... | |
80 | 80 |
self.object.remove_authorized_role(role) |
81 | 81 |
else: |
82 | 82 |
messages.warning(self.request, _('You are not authorized')) |
83 |
return super(ServiceView, self).form_valid(form)
|
|
83 |
return super().form_valid(form) |
|
84 | 84 | |
85 | 85 |
def get_context_data(self, **kwargs): |
86 | 86 |
kwargs['form'] = self.get_form() |
87 |
ctx = super(ServiceView, self).get_context_data(**kwargs)
|
|
87 |
ctx = super().get_context_data(**kwargs) |
|
88 | 88 |
ctx['roles_table'] = tables.RoleTable(self.object.roles.all()) |
89 | 89 |
return ctx |
90 | 90 |
src/authentic2/manager/tables.py | ||
---|---|---|
33 | 33 |
class PermissionLinkColumn(tables.LinkColumn): |
34 | 34 |
def __init__(self, viewname, **kwargs): |
35 | 35 |
self.permission = kwargs.pop('permission', None) |
36 |
super(PermissionLinkColumn, self).__init__(viewname, **kwargs)
|
|
36 |
super().__init__(viewname, **kwargs) |
|
37 | 37 | |
38 | 38 |
def render(self, value, record, bound_column, **kwargs): |
39 | 39 |
if self.permission: |
40 | 40 |
request = StoreRequestMiddleware.get_request() |
41 | 41 |
if request and not request.user.has_perm(self.permission, record): |
42 | 42 |
return value |
43 |
return super(PermissionLinkColumn, self).render(value, record, bound_column)
|
|
43 |
return super().render(value, record, bound_column) |
|
44 | 44 | |
45 | 45 | |
46 | 46 |
class VerifiableEmailColumn(tables.Column): |
src/authentic2/manager/user_export.py | ||
---|---|---|
34 | 34 |
user_resource = UserResource() |
35 | 35 |
fields = user_resource._meta.export_order + ('email_verified', 'is_active', 'modified') |
36 | 36 |
attributes = [attr.name for attr in Attribute.objects.all()] |
37 |
headers = fields + tuple(['attribute_%s' % attr for attr in attributes])
|
|
37 |
headers = fields + tuple('attribute_%s' % attr for attr in attributes)
|
|
38 | 38 | |
39 | 39 |
at_mapping = {a.id: a for a in Attribute.objects.all()} |
40 | 40 |
avs = ( |
... | ... | |
79 | 79 |
return dataset |
80 | 80 | |
81 | 81 | |
82 |
class UserExport(object):
|
|
82 |
class UserExport: |
|
83 | 83 |
def __init__(self, uuid): |
84 | 84 |
self.uuid = uuid |
85 | 85 |
self.path = os.path.join(self.base_path(), self.uuid) |
... | ... | |
105 | 105 | |
106 | 106 |
@property |
107 | 107 |
def csv(self): |
108 |
return open(self.export_path, 'r')
|
|
108 |
return open(self.export_path) |
|
109 | 109 | |
110 | 110 |
def set_export_content(self, content): |
111 | 111 |
with open(self.export_path, 'w') as f: |
... | ... | |
115 | 115 |
def progress(self): |
116 | 116 |
progress = 0 |
117 | 117 |
if os.path.exists(self.progress_path): |
118 |
with open(self.progress_path, 'r') as f:
|
|
118 |
with open(self.progress_path) as f: |
|
119 | 119 |
progress = f.read() |
120 | 120 |
return int(progress) if progress else 0 |
121 | 121 |
src/authentic2/manager/user_import.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import unicode_literals |
|
18 | 17 | |
19 | 18 |
import base64 |
20 | 19 |
import contextlib |
... | ... | |
43 | 42 |
return base64.b32encode(uuid.uuid4().bytes).strip(b'=').lower().decode('ascii') |
44 | 43 | |
45 | 44 | |
46 |
class UserImport(object):
|
|
45 |
class UserImport: |
|
47 | 46 |
def __init__(self, uuid): |
48 | 47 |
self.uuid = uuid |
49 | 48 |
self.path = os.path.join(self.base_path(), self.uuid) |
... | ... | |
118 | 117 |
shutil.rmtree(self.path) |
119 | 118 | |
120 | 119 | |
121 |
class Report(object):
|
|
120 |
class Report: |
|
122 | 121 |
STATE_WAITING = 'waiting' |
123 | 122 |
STATE_RUNNING = 'running' |
124 | 123 |
STATE_FINISHED = 'finished' |
... | ... | |
276 | 275 |
os.unlink(self.path) |
277 | 276 | |
278 | 277 | |
279 |
class Reports(object):
|
|
278 |
class Reports: |
|
280 | 279 |
PREFIX = 'report-' |
281 | 280 | |
282 | 281 |
def __init__(self, user_import): |
src/authentic2/manager/user_views.py | ||
---|---|---|
106 | 106 |
return self.search_form.is_valid() and self.search_form.cleaned_data.get('ou') |
107 | 107 | |
108 | 108 |
def get_queryset(self): |
109 |
qs = super(UsersView, self).get_queryset()
|
|
109 |
qs = super().get_queryset() |
|
110 | 110 |
qs = qs.select_related('ou') |
111 | 111 |
qs = qs.prefetch_related('roles', 'roles__parent_relation__parent') |
112 | 112 |
return qs |
113 | 113 | |
114 | 114 |
def get_search_form_kwargs(self): |
115 |
kwargs = super(UsersView, self).get_search_form_kwargs()
|
|
115 |
kwargs = super().get_search_form_kwargs() |
|
116 | 116 |
kwargs['minimum_chars'] = app_settings.USER_SEARCH_MINIMUM_CHARS |
117 | 117 |
kwargs['show_all_ou'] = app_settings.SHOW_ALL_OU |
118 | 118 |
return kwargs |
119 | 119 | |
120 | 120 |
def filter_by_search(self, qs): |
121 |
qs = super(UsersView, self).filter_by_search(qs)
|
|
121 |
qs = super().filter_by_search(qs) |
|
122 | 122 |
if not self.search_form.is_valid(): |
123 | 123 |
qs = qs.filter(ou=self.request.user.ou) |
124 | 124 |
return qs |
... | ... | |
131 | 131 |
exclude = kwargs.setdefault('exclude', []) |
132 | 132 |
if 'username' not in exclude: |
133 | 133 |
exclude.append('username') |
134 |
table = super(UsersView, self).get_table(**kwargs)
|
|
134 |
table = super().get_table(**kwargs) |
|
135 | 135 |
if self.search_form.not_enough_chars(): |
136 | 136 |
user_qs = self.search_form.filter_by_ou(self.get_queryset()) |
137 | 137 |
table.empty_text = _('Enter at least %(limit)d characters ' '(%(user_count)d users)') % { |
... | ... | |
142 | 142 |
return table |
143 | 143 | |
144 | 144 |
def get_context_data(self, **kwargs): |
145 |
ctx = super(UsersView, self).get_context_data()
|
|
145 |
ctx = super().get_context_data() |
|
146 | 146 |
if get_ou_count() < 2: |
147 | 147 |
ou = get_default_ou() |
148 | 148 |
else: |
... | ... | |
195 | 195 |
return super().dispatch(request, *args, **kwargs) |
196 | 196 | |
197 | 197 |
def get_form_kwargs(self): |
198 |
kwargs = super(UserAddView, self).get_form_kwargs()
|
|
198 |
kwargs = super().get_form_kwargs() |
|
199 | 199 |
kwargs['ou'] = self.ou |
200 | 200 |
return kwargs |
201 | 201 | |
... | ... | |
223 | 223 |
) |
224 | 224 | |
225 | 225 |
def get_context_data(self, **kwargs): |
226 |
context = super(UserAddView, self).get_context_data(**kwargs)
|
|
226 |
context = super().get_context_data(**kwargs) |
|
227 | 227 |
context['cancel_url'] = select_next_url(self.request, default='../..', field_name='cancel') |
228 | 228 |
context['next'] = select_next_url(self.request, default=None, include_post=True) |
229 | 229 |
context['ou'] = self.ou |
... | ... | |
245 | 245 |
self.duplicate_users = duplicate_users |
246 | 246 |
return self.form_invalid(form) |
247 | 247 | |
248 |
response = super(UserAddView, self).form_valid(form)
|
|
248 |
response = super().form_valid(form) |
|
249 | 249 |
hooks.call_hooks( |
250 | 250 |
'event', name='manager-add-user', user=self.request.user, instance=form.instance, form=form |
251 | 251 |
) |
... | ... | |
253 | 253 |
return response |
254 | 254 | |
255 | 255 |
def get_initial(self, *args, **kwargs): |
256 |
initial = super(UserAddView, self).get_initial(*args, **kwargs)
|
|
256 |
initial = super().get_initial(*args, **kwargs) |
|
257 | 257 |
initial.update(self.get_user_add_policies()) |
258 | 258 |
return initial |
259 | 259 | |
... | ... | |
314 | 314 |
return OIDCClient.objects.exists() |
315 | 315 | |
316 | 316 |
def get_other_actions(self): |
317 |
for action in super(UserDetailView, self).get_other_actions(): |
|
318 |
yield action |
|
317 |
yield from super().get_other_actions() |
|
319 | 318 |
yield Action('password_reset', _('Reset password'), permission='custom_user.reset_password_user') |
320 | 319 |
if self.object.is_active: |
321 | 320 |
yield Action('deactivate', _('Suspend'), permission='custom_user.activate_user') |
... | ... | |
412 | 411 |
return fields |
413 | 412 | |
414 | 413 |
def get_form(self, *args, **kwargs): |
415 |
form = super(UserDetailView, self).get_form(*args, **kwargs)
|
|
414 |
form = super().get_form(*args, **kwargs) |
|
416 | 415 |
if 'email' in form.fields: |
417 | 416 |
if self.object.email_verified: |
418 | 417 |
comment = _('Email verified') |
... | ... | |
449 | 448 |
data for datas in hooks.call_hooks('manager_user_data', self, self.object) for data in datas |
450 | 449 |
] |
451 | 450 |
kwargs['user_data'] = user_data |
452 |
ctx = super(UserDetailView, self).get_context_data(**kwargs)
|
|
451 |
ctx = super().get_context_data(**kwargs) |
|
453 | 452 |
return ctx |
454 | 453 | |
455 | 454 | |
... | ... | |
486 | 485 |
) |
487 | 486 | |
488 | 487 |
def get_context_data(self, **kwargs): |
489 |
context = super(UserEditView, self).get_context_data(**kwargs)
|
|
488 |
context = super().get_context_data(**kwargs) |
|
490 | 489 |
next_url = self._get_next_url() |
491 | 490 |
context['next'] = next_url |
492 | 491 |
context['cancel_url'] = next_url |
... | ... | |
499 | 498 |
if 'email' in form.changed_data: |
500 | 499 |
self.object.email_verified = False |
501 | 500 |
self.object.save() |
502 |
response = super(UserEditView, self).form_valid(form)
|
|
501 |
response = super().form_valid(form) |
|
503 | 502 |
if form.has_changed(): |
504 | 503 |
hooks.call_hooks( |
505 | 504 |
'event', name='manager-edit-user', user=self.request.user, instance=form.instance, form=form |
... | ... | |
581 | 580 |
return ugettext('New password set') |
582 | 581 | |
583 | 582 |
def form_valid(self, form): |
584 |
response = super(UserChangePasswordView, self).form_valid(form)
|
|
583 |
response = super().form_valid(form) |
|
585 | 584 |
hooks.call_hooks( |
586 | 585 |
'event', name='manager-change-password', user=self.request.user, instance=form.instance, form=form |
587 | 586 |
) |
... | ... | |
607 | 606 |
return None |
608 | 607 | |
609 | 608 |
def form_valid(self, form): |
610 |
response = super(UserChangeEmailView, self).form_valid(form)
|
|
609 |
response = super().form_valid(form) |
|
611 | 610 |
new_email = form.cleaned_data['new_email'] |
612 | 611 |
hooks.call_hooks( |
613 | 612 |
'event', |
... | ... | |
669 | 668 |
return self.object.roles_and_parents() |
670 | 669 | |
671 | 670 |
def get_table_data(self): |
672 |
qs = super(UserRolesView, self).get_table_data()
|
|
671 |
qs = super().get_table_data() |
|
673 | 672 |
if self.is_ou_specified(): |
674 | 673 |
qs = list(qs) |
675 | 674 |
return qs |
676 | 675 | |
677 | 676 |
def authorize(self, request, *args, **kwargs): |
678 |
response = super(UserRolesView, self).authorize(request, *args, **kwargs)
|
|
677 |
response = super().authorize(request, *args, **kwargs) |
|
679 | 678 |
if response is not None: |
680 | 679 |
return response |
681 | 680 |
if not UserDetailView.has_perm_on_roles(request.user, self.object): |
... | ... | |
703 | 702 |
'event', name='manager-remove-role-member', user=self.request.user, role=role, member=user |
704 | 703 |
) |
705 | 704 |
self.request.journal.record('manager.role.membership.removal', member=user, role=role) |
706 |
return super(UserRolesView, self).form_valid(form)
|
|
705 |
return super().form_valid(form) |
|
707 | 706 | |
708 | 707 |
def get_search_form_kwargs(self): |
709 |
kwargs = super(UserRolesView, self).get_search_form_kwargs()
|
|
708 |
kwargs = super().get_search_form_kwargs() |
|
710 | 709 |
kwargs['all_ou_label'] = '' |
711 | 710 |
kwargs['user'] = self.object |
712 | 711 |
kwargs['role_members_from_ou'] = app_settings.ROLE_MEMBERS_FROM_OU |
... | ... | |
720 | 719 |
return kwargs |
721 | 720 | |
722 | 721 |
def get_form_kwargs(self): |
723 |
kwargs = super(UserRolesView, self).get_form_kwargs()
|
|
722 |
kwargs = super().get_form_kwargs() |
|
724 | 723 |
# if role members can only be from the same OU, we filter roles based on the user's ou |
725 | 724 |
if app_settings.ROLE_MEMBERS_FROM_OU and self.object.ou_id: |
726 | 725 |
kwargs['ou'] = self.object.ou |
... | ... | |
760 | 759 |
uuid = request.POST['delete'] |
761 | 760 |
user_import.UserImport(uuid).delete() |
762 | 761 |
return redirect(self.request, 'a2-manager-users-imports') |
763 |
return super(UserImportsView, self).post(request, *args, **kwargs)
|
|
762 |
return super().post(request, *args, **kwargs) |
|
764 | 763 | |
765 | 764 |
def form_valid(self, form): |
766 | 765 |
user_import = form.save() |
... | ... | |
772 | 771 |
def get_context_data(self, **kwargs): |
773 | 772 |
from authentic2.manager import user_import |
774 | 773 | |
775 |
ctx = super(UserImportsView, self).get_context_data(**kwargs)
|
|
774 |
ctx = super().get_context_data(**kwargs) |
|
776 | 775 |
ctx['imports'] = sorted( |
777 | 776 |
user_import.UserImport.all(), key=operator.attrgetter('created'), reverse=True |
778 | 777 |
) |
... | ... | |
845 | 844 |
if self.user_import.encoding == 'utf-8': |
846 | 845 |
with self.user_import.meta_update as meta: |
847 | 846 |
meta['encoding'] = 'utf-8-sig' |
848 |
return super(UserImportView, self).dispatch(request, uuid, **kwargs)
|
|
847 |
return super().dispatch(request, uuid, **kwargs) |
|
849 | 848 | |
850 | 849 |
def get(self, request, uuid, filename=None): |
851 | 850 |
if filename: |
852 | 851 |
return FileResponse(self.user_import.import_file, content_type='text/csv') |
853 |
return super(UserImportView, self).get(request, uuid=uuid, filename=filename)
|
|
852 |
return super().get(request, uuid=uuid, filename=filename) |
|
854 | 853 | |
855 | 854 |
def post(self, request, *args, **kwargs): |
856 | 855 |
from authentic2.manager import user_import |
... | ... | |
870 | 869 |
return redirect(request, 'a2-manager-users-import', kwargs={'uuid': self.user_import.uuid}) |
871 | 870 | |
872 | 871 |
def get_context_data(self, **kwargs): |
873 |
ctx = super(UserImportView, self).get_context_data(**kwargs)
|
|
872 |
ctx = super().get_context_data(**kwargs) |
|
874 | 873 |
ctx['encoding'] = [encoding for id, encoding in ENCODINGS if id == self.user_import.encoding][0] |
875 | 874 |
ctx['user_import'] = self.user_import |
876 | 875 |
ctx['reports'] = sorted(self.user_import.reports, key=operator.attrgetter('created'), reverse=True) |
... | ... | |
894 | 893 |
self.report = self.user_import.reports[report_uuid] |
895 | 894 |
except KeyError: |
896 | 895 |
raise Http404 |
897 |
return super(UserImportReportView, self).dispatch(request, import_uuid, report_uuid)
|
|
896 |
return super().dispatch(request, import_uuid, report_uuid) |
|
898 | 897 | |
899 | 898 |
def get_context_data(self, **kwargs): |
900 |
ctx = super(UserImportReportView, self).get_context_data(**kwargs)
|
|
899 |
ctx = super().get_context_data(**kwargs) |
|
901 | 900 |
ctx['user_import'] = self.user_import |
902 | 901 |
ctx['report'] = self.report |
903 | 902 |
if self.report.simulate: |
... | ... | |
934 | 933 |
def dispatch(self, request, *args, **kwargs): |
935 | 934 |
if not request.user.is_superuser: |
936 | 935 |
raise PermissionDenied |
937 |
return super(UserSuView, self).dispatch(request, *args, **kwargs)
|
|
936 |
return super().dispatch(request, *args, **kwargs) |
|
938 | 937 | |
939 | 938 |
def get_context_data(self, **kwargs): |
940 |
ctx = super(UserSuView, self).get_context_data(**kwargs)
|
|
939 |
ctx = super().get_context_data(**kwargs) |
|
941 | 940 |
ctx['su_url'] = make_url( |
942 | 941 |
'auth_logout', |
943 | 942 |
params={REDIRECT_FIELD_NAME: switch_user.build_url(self.object, self.duration)}, |
... | ... | |
972 | 971 |
return qs |
973 | 972 | |
974 | 973 |
def form_valid(self, form): |
975 |
response = super(UserAuthorizationsView, self).form_valid(form)
|
|
974 |
response = super().form_valid(form) |
|
976 | 975 |
auth_id = form.cleaned_data['authorization'] |
977 | 976 |
if self.can_manage_authorizations: |
978 | 977 |
qs = OIDCAuthorization.objects.filter(user=self.get_object()) |
src/authentic2/manager/utils.py | ||
---|---|---|
25 | 25 |
if user.first_name or user.last_name: |
26 | 26 |
labels.append(user.first_name) |
27 | 27 |
if user.first_name and user.last_name: |
28 |
labels.append(u' ')
|
|
28 |
labels.append(' ') |
|
29 | 29 |
labels.append(user.last_name) |
30 | 30 |
if user.email and user.email not in labels: |
31 | 31 |
if labels: |
32 |
labels.append(u' - ')
|
|
32 |
labels.append(' - ') |
|
33 | 33 |
labels.append(user.email) |
34 | 34 |
if user.username and user.username not in labels: |
35 | 35 |
if labels: |
36 |
labels.append(u' - ')
|
|
36 |
labels.append(' - ') |
|
37 | 37 |
labels.append(user.username) |
38 | 38 |
return ''.join(labels) |
39 | 39 |
src/authentic2/manager/views.py | ||
---|---|---|
53 | 53 |
pass |
54 | 54 | |
55 | 55 | |
56 |
class MultipleOUMixin(object):
|
|
56 |
class MultipleOUMixin: |
|
57 | 57 |
'''Tell templates if there are multiple OU for adaptation in breadcrumbs for example''' |
58 | 58 | |
59 | 59 |
def get_context_data(self, **kwargs): |
60 | 60 |
kwargs['multiple_ou'] = utils.get_ou_count() > 1 |
61 |
return super(MultipleOUMixin, self).get_context_data(**kwargs)
|
|
61 |
return super().get_context_data(**kwargs) |
|
62 | 62 | |
63 | 63 | |
64 |
class MediaMixin(object, metaclass=MediaMixinBase):
|
|
64 |
class MediaMixin(metaclass=MediaMixinBase): |
|
65 | 65 |
'''Expose needed CSS and JS files as a media object''' |
66 | 66 | |
67 | 67 |
class Media: |
... | ... | |
79 | 79 | |
80 | 80 |
def get_context_data(self, **kwargs): |
81 | 81 |
kwargs['media'] = self.media |
82 |
ctx = super(MediaMixin, self).get_context_data(**kwargs)
|
|
82 |
ctx = super().get_context_data(**kwargs) |
|
83 | 83 |
if 'form' in ctx: |
84 | 84 |
ctx['media'] += ctx['form'].media |
85 | 85 |
return ctx |
86 | 86 | |
87 | 87 | |
88 |
class PermissionMixin(object):
|
|
88 |
class PermissionMixin: |
|
89 | 89 |
'''Control access to views based on permissions''' |
90 | 90 | |
91 | 91 |
permissions = None |
... | ... | |
121 | 121 |
response = self.authorize(request, *args, **kwargs) |
122 | 122 |
if response is not None: |
123 | 123 |
return response |
124 |
return super(PermissionMixin, self).dispatch(request, *args, **kwargs)
|
|
124 |
return super().dispatch(request, *args, **kwargs) |
|
125 | 125 | |
126 | 126 | |
127 | 127 |
def filter_view(request, qs): |
... | ... | |
130 | 130 |
return request.user.filter_by_perm(perm, qs) |
131 | 131 | |
132 | 132 | |
133 |
class FilterQuerysetByPermMixin(object):
|
|
133 |
class FilterQuerysetByPermMixin: |
|
134 | 134 |
def get_queryset(self): |
135 |
qs = super(FilterQuerysetByPermMixin, self).get_queryset()
|
|
135 |
qs = super().get_queryset() |
|
136 | 136 |
return filter_view(self.request, qs) |
137 | 137 | |
138 | 138 | |
139 |
class FilterTableQuerysetByPermMixin(object):
|
|
139 |
class FilterTableQuerysetByPermMixin: |
|
140 | 140 |
def get_table_data(self): |
141 |
qs = super(FilterTableQuerysetByPermMixin, self).get_table_data()
|
|
141 |
qs = super().get_table_data() |
|
142 | 142 |
if getattr(self, 'filter_table_by_perm', True): |
143 | 143 |
qs = filter_view(self.request, qs) |
144 | 144 |
return qs |
145 | 145 | |
146 | 146 | |
147 |
class TableQuerysetMixin(object):
|
|
147 |
class TableQuerysetMixin: |
|
148 | 148 |
def get_table_queryset(self): |
149 | 149 |
return self.get_queryset() |
150 | 150 | |
... | ... | |
152 | 152 |
return self.get_table_queryset() |
153 | 153 | |
154 | 154 | |
155 |
class SearchFormMixin(object):
|
|
155 |
class SearchFormMixin: |
|
156 | 156 |
"""Handle a search form on the current table view. |
157 | 157 | |
158 | 158 |
The search form class must implement a .filter(qs) method returning a new queryset.""" |
... | ... | |
173 | 173 | |
174 | 174 |
def dispatch(self, request, *args, **kwargs): |
175 | 175 |
self.search_form = self.get_search_form() |
176 |
return super(SearchFormMixin, self).dispatch(request, *args, **kwargs)
|
|
176 |
return super().dispatch(request, *args, **kwargs) |
|
177 | 177 | |
178 | 178 |
def get_context_data(self, **kwargs): |
179 |
ctx = super(SearchFormMixin, self).get_context_data(**kwargs)
|
|
179 |
ctx = super().get_context_data(**kwargs) |
|
180 | 180 |
if self.search_form: |
181 | 181 |
ctx['search_form'] = self.search_form |
182 | 182 |
return ctx |
... | ... | |
187 | 187 |
return qs |
188 | 188 | |
189 | 189 |
def get_table_data(self): |
190 |
qs = super(SearchFormMixin, self).get_table_data()
|
|
190 |
qs = super().get_table_data() |
|
191 | 191 |
qs = self.filter_by_search(qs) |
192 | 192 |
return qs |
193 | 193 | |
194 | 194 | |
195 |
class FormatsContextData(object):
|
|
195 |
class FormatsContextData: |
|
196 | 196 |
'''Export list of supported formats in context''' |
197 | 197 | |
198 | 198 |
formats = ['csv'] |
199 | 199 | |
200 | 200 |
def get_context_data(self, **kwargs): |
201 |
ctx = super(FormatsContextData, self).get_context_data(**kwargs)
|
|
201 |
ctx = super().get_context_data(**kwargs) |
|
202 | 202 |
ctx['formats'] = self.formats |
203 | 203 |
return ctx |
204 | 204 | |
205 | 205 | |
206 |
class Action(object):
|
|
206 |
class Action: |
|
207 | 207 |
'''Describe an action for view supporting multiples actions.''' |
208 | 208 | |
209 | 209 |
name = None |
... | ... | |
238 | 238 |
return True |
239 | 239 | |
240 | 240 | |
241 |
class AjaxFormViewMixin(object):
|
|
241 |
class AjaxFormViewMixin: |
|
242 | 242 |
'''Implement a JSON response for view which can be included in an AJAX popup''' |
243 | 243 | |
244 | 244 |
success_url = '.' |
245 | 245 | |
246 | 246 |
def dispatch(self, request, *args, **kwargs): |
247 |
response = super(AjaxFormViewMixin, self).dispatch(request, *args, **kwargs)
|
|
247 |
response = super().dispatch(request, *args, **kwargs) |
|
248 | 248 |
return self.return_ajax_response(request, response) |
249 | 249 | |
250 | 250 |
def return_ajax_response(self, request, response): |
... | ... | |
269 | 269 |
return HttpResponse(json.dumps(data), content_type='application/json') |
270 | 270 | |
271 | 271 | |
272 |
class TitleMixin(object):
|
|
272 |
class TitleMixin: |
|
273 | 273 |
'''Mixin to provide a title to the view's template''' |
274 | 274 | |
275 | 275 |
title = '' |
276 | 276 | |
277 | 277 |
def get_context_data(self, **kwargs): |
278 |
ctx = super(TitleMixin, self).get_context_data(**kwargs)
|
|
278 |
ctx = super().get_context_data(**kwargs) |
|
279 | 279 |
ctx['title'] = self.title |
280 | 280 |
ctx['manager_site_title'] = app_settings.SITE_TITLE |
281 | 281 |
return ctx |
282 | 282 | |
283 | 283 | |
284 |
class ActionMixin(object):
|
|
284 |
class ActionMixin: |
|
285 | 285 |
'''Describe the main action implementd by a view''' |
286 | 286 | |
287 | 287 |
action = None |
288 | 288 | |
289 | 289 |
def get_context_data(self, **kwargs): |
290 |
ctx = super(ActionMixin, self).get_context_data(**kwargs)
|
|
290 |
ctx = super().get_context_data(**kwargs) |
|
291 | 291 |
if self.action: |
292 | 292 |
ctx['action'] = self.action |
293 | 293 |
return ctx |
294 | 294 | |
295 | 295 | |
296 |
class OtherActionsMixin(object):
|
|
296 |
class OtherActionsMixin: |
|
297 | 297 |
'''Describe secondary actions possible on a view''' |
298 | 298 | |
299 | 299 |
other_actions = None |
300 | 300 | |
301 | 301 |
def get_context_data(self, **kwargs): |
302 |
ctx = super(OtherActionsMixin, self).get_context_data(**kwargs)
|
|
302 |
ctx = super().get_context_data(**kwargs) |
|
303 | 303 |
ctx['other_actions'] = tuple(self.get_displayed_other_actions()) |
304 | 304 |
return ctx |
305 | 305 | |
... | ... | |
340 | 340 |
return response |
341 | 341 |
self.request.method = 'GET' |
342 | 342 |
return self.get(request, *args, **kwargs) |
343 |
parent = super(OtherActionsMixin, self)
|
|
343 |
parent = super() |
|
344 | 344 |
if hasattr(parent, 'post'): |
345 | 345 |
return parent.post(request, *args, **kwargs) |
346 | 346 |
return self.get(request, *args, **kwargs) |
347 | 347 | |
348 | 348 | |
349 |
class ExportMixin(object):
|
|
349 |
class ExportMixin: |
|
350 | 350 |
'''Help in implementd export views''' |
351 | 351 | |
352 | 352 |
http_method_names = ['get', 'head', 'options'] |
... | ... | |
383 | 383 |
return response |
384 | 384 | |
385 | 385 | |
386 |
class FormNeedsRequest(object):
|
|
386 |
class FormNeedsRequest: |
|
387 | 387 |
def get_form_kwargs(self): |
388 |
kwargs = super(FormNeedsRequest, self).get_form_kwargs()
|
|
388 |
kwargs = super().get_form_kwargs() |
|
389 | 389 |
if getattr(self.get_form_class(), 'need_request', False): |
390 | 390 |
kwargs['request'] = self.request |
391 | 391 |
return kwargs |
... | ... | |
403 | 403 |
return '' |
404 | 404 | |
405 | 405 |
def get_context_data(self, **kwargs): |
406 |
ctx = super(ModelNameMixin, self).get_context_data(**kwargs)
|
|
406 |
ctx = super().get_context_data(**kwargs) |
|
407 | 407 |
ctx['model_name'] = self.get_model_name() |
408 | 408 |
return ctx |
409 | 409 | |
410 | 410 | |
411 |
class TableHookMixin(object):
|
|
411 |
class TableHookMixin: |
|
412 | 412 |
'''Helper class for table views, hiding the OU column from tables if an OU filter exists''' |
413 | 413 | |
414 | 414 |
def get_table(self, **kwargs): |
415 |
table = super(TableHookMixin, self).get_table(**kwargs)
|
|
415 |
table = super().get_table(**kwargs) |
|
416 | 416 |
import copy |
417 | 417 | |
418 | 418 |
table = copy.deepcopy(table) |
... | ... | |
500 | 500 |
return modelform_factory(self.model, form=self.form_class, fields=self.get_fields()) |
501 | 501 | |
502 | 502 |
def get_form(self, form_class=None): |
503 |
form = super(ModelFormView, self).get_form(form_class=form_class)
|
|
503 |
form = super().get_form(form_class=form_class) |
|
504 | 504 |
hooks.call_hooks('manager_modify_form', self, form) |
505 | 505 |
return form |
506 | 506 | |
... | ... | |
532 | 532 |
form = self.get_form() |
533 | 533 |
hooks.call_hooks('manager_modify_form', self, form) |
534 | 534 |
kwargs['form'] = form |
535 |
ctx = super(BaseDetailView, self).get_context_data(**kwargs)
|
|
535 |
ctx = super().get_context_data(**kwargs) |
|
536 | 536 |
return ctx |
537 | 537 | |
538 | 538 | |
... | ... | |
553 | 553 | |
554 | 554 |
@property |
555 | 555 |
def title(self): |
556 |
return ('Add %s') % super(BaseAddView, self).get_model_name()
|
|
556 |
return ('Add %s') % super().get_model_name() |
|
557 | 557 | |
558 | 558 |
def get_success_url(self): |
559 | 559 |
return reverse(self.success_view_name, kwargs={'pk': self.object.pk}) |
... | ... | |
634 | 634 |
def dispatch(self, request, *args, **kwargs): |
635 | 635 |
if app_settings.HOMEPAGE_URL: |
636 | 636 |
return redirect(request, app_settings.HOMEPAGE_URL) |
637 |
return super(HomepageView, self).dispatch(request, *args, **kwargs)
|
|
637 |
return super().dispatch(request, *args, **kwargs) |
|
638 | 638 | |
639 | 639 |
def get_homepage_entries(self): |
640 | 640 |
entries = [] |
... | ... | |
661 | 661 |
kwargs['can_view_journal'] = self.request.user.has_perms( |
662 | 662 |
['custom_user.view_user', 'a2_rbac.view_role'] |
663 | 663 |
) |
664 |
return super(HomepageView, self).get_context_data(**kwargs)
|
|
664 |
return super().get_context_data(**kwargs) |
|
665 | 665 | |
666 | 666 | |
667 | 667 |
homepage = HomepageView.as_view() |
... | ... | |
686 | 686 |
menu_json = json_view(MenuJson.as_view()) |
687 | 687 | |
688 | 688 | |
689 |
class HideOUColumnMixin(object):
|
|
689 |
class HideOUColumnMixin: |
|
690 | 690 |
'''Helper class for table views, hiding the OU column from tables if an OU filter exists''' |
691 | 691 | |
692 | 692 |
def get_table(self, **kwargs): |
... | ... | |
704 | 704 |
exclude = kwargs.setdefault('exclude', []) |
705 | 705 |
if 'ou' not in exclude: |
706 | 706 |
exclude.append('ou') |
707 |
return super(HideOUColumnMixin, self).get_table(**kwargs)
|
|
707 |
return super().get_table(**kwargs) |
|
708 | 708 | |
709 | 709 | |
710 | 710 |
class Select2View(AutoResponseView): |
... | ... | |
763 | 763 |
form.add_error('site_json', e) |
764 | 764 |
return self.form_invalid(form) |
765 | 765 | |
766 |
return super(SiteImportView, self).form_valid(form)
|
|
766 |
return super().form_valid(form) |
|
767 | 767 | |
768 | 768 |
def dispatch(self, request, *args, **kwargs): |
769 | 769 |
if not request.user.is_superuser: |
770 | 770 |
raise PermissionDenied |
771 |
return super(SiteImportView, self).dispatch(request, *args, **kwargs)
|
|
771 |
return super().dispatch(request, *args, **kwargs) |
|
772 | 772 | |
773 | 773 | |
774 | 774 |
site_import = SiteImportView.as_view() |
src/authentic2/manager/widgets.py | ||
---|---|---|
30 | 30 |
from . import utils |
31 | 31 | |
32 | 32 | |
33 |
class SplitTermMixin(object):
|
|
33 |
class SplitTermMixin: |
|
34 | 34 |
split_term_operator = operator.__or__ |
35 | 35 | |
36 | 36 |
def filter_queryset(self, term, queryset=None): |
... | ... | |
42 | 42 |
return qs.all() |
43 | 43 |
queries = [] |
44 | 44 |
for term in term.split(): |
45 |
queries.append(super(SplitTermMixin, self).filter_queryset(term, queryset=qs))
|
|
45 |
queries.append(super().filter_queryset(term, queryset=qs)) |
|
46 | 46 |
qs = functools.reduce(self.split_term_operator, queries) |
47 | 47 |
return qs |
48 | 48 | |
49 | 49 | |
50 |
class Select2Mixin(object):
|
|
50 |
class Select2Mixin: |
|
51 | 51 |
class Media: |
52 | 52 |
js = ('authentic2/manager/js/select2_locale.js',) |
53 | 53 | |
54 | 54 |
def build_attrs(self, *args, **kwargs): |
55 |
attrs = super(Select2Mixin, self).build_attrs(*args, **kwargs)
|
|
55 |
attrs = super().build_attrs(*args, **kwargs) |
|
56 | 56 |
field_data = { |
57 | 57 |
'class': self.__class__.__name__, |
58 | 58 |
'where_clause': force_text(base64.b64encode(pickle.dumps(self.queryset.query.where))), |
... | ... | |
106 | 106 |
def label_from_instance(self, obj): |
107 | 107 |
label = str(obj) |
108 | 108 |
if obj.ou and utils.get_ou_count() > 1: |
109 |
label = '{ou} - {obj}'.format(ou=obj.ou, obj=obj)
|
|
109 |
label = f'{obj.ou} - {obj}'
|
|
110 | 110 |
return label |
111 | 111 | |
112 | 112 |
src/authentic2/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/migrations/0002_auto_20150320_1418.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/migrations/0003_auto_20150409_1840.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/migrations/0004_service.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/migrations/0005_service_ou.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 | |
... | ... | |
23 | 20 |
), |
24 | 21 |
migrations.AlterUniqueTogether( |
25 | 22 |
name='service', |
26 |
unique_together=set([('slug', 'ou')]),
|
|
23 |
unique_together={('slug', 'ou')},
|
|
27 | 24 |
), |
28 | 25 |
] |
src/authentic2/migrations/0006_conditional_slug_index.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations |
5 | 2 | |
6 | 3 |
from authentic2.migrations import CreatePartialIndexes |
src/authentic2/migrations/0007_auto_20150523_0028.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/migrations/0008_auto_20160204_1415.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/migrations/0009_auto_20160211_2247.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/migrations/0010_attributevalue_multiple.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/migrations/0011_auto_20160211_2253.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/migrations/0012_auto_20160211_2255.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
import django |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/migrations/0013_auto_20160211_2258.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
from authentic2.migrations import CreatePartialIndexes |
... | ... | |
15 | 12 |
operations = [ |
16 | 13 |
migrations.AlterUniqueTogether( |
17 | 14 |
name='attributevalue', |
18 |
unique_together=set([('content_type', 'object_id', 'attribute', 'multiple', 'content')]),
|
|
15 |
unique_together={('content_type', 'object_id', 'attribute', 'multiple', 'content')},
|
|
19 | 16 |
), |
20 | 17 |
CreatePartialIndexes( |
21 | 18 |
'AttributeValue', |
src/authentic2/migrations/0014_attributevalue_verified.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/migrations/0015_auto_20160621_1711.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/migrations/0016_attribute_disabled.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/migrations/0017_modify_attribute_serialization.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
import json |
3 | 2 | |
4 | 3 |
from django.db import migrations |
src/authentic2/migrations/0018_auto_20170524_0842.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/migrations/0019_auto_20170309_1529.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/migrations/0020_delete_federatedid.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/migrations/0021_attribute_order.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
import django.db.models.manager |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2/migrations/0022_attribute_scopes.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/migrations/0023_auto_20181031_0900.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.12 on 2018-10-31 08:00 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations, models |
6 | 4 |
src/authentic2/migrations/0024_auto_20190617_1113.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.20 on 2019-06-17 09:13 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations |
6 | 4 | |
... | ... | |
23 | 21 |
), |
24 | 22 |
migrations.AlterUniqueTogether( |
25 | 23 |
name='userexternalid', |
26 |
unique_together=set([('source', 'external_id')]),
|
|
24 |
unique_together={('source', 'external_id')},
|
|
27 | 25 |
), |
28 | 26 |
] |
src/authentic2/migrations/0025_auto_20191009_1047.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.20 on 2019-10-09 08:47 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
import django.db.models.deletion |
6 | 4 |
from django.conf import settings |
src/authentic2/migrations/0026_token.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.20 on 2020-02-11 10:27 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
import uuid |
6 | 4 |
src/authentic2/migrations/0027_remove_deleteduser.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.29 on 2020-04-21 14:09 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations, models |
6 | 4 |
src/authentic2/migrations/0028_trigram_unaccent_index.py | ||
---|---|---|
1 | 1 |
# Generated by Django 1.11.18 on 2020-09-17 15:38 |
2 |
from __future__ import unicode_literals |
|
3 | 2 | |
4 | 3 |
from django.db import migrations |
5 | 4 |
src/authentic2/migrations/0029_auto_20201013_1614.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.18 on 2020-10-13 14:14 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations |
6 | 4 |
src/authentic2/models.py | ||
---|---|---|
56 | 56 |
updated = models.DateTimeField(auto_now=True, verbose_name=_('last update date')) |
57 | 57 | |
58 | 58 |
def __str__(self): |
59 |
return '{0} is {1} on {2}'.format(self.user, self.external_id, self.source)
|
|
59 |
return f'{self.user} is {self.external_id} on {self.source}'
|
|
60 | 60 | |
61 | 61 |
def __repr__(self): |
62 |
return ( |
|
63 |
'<UserExternalId user: {0!r} source: {1!r} ' |
|
64 |
'external_id: {2!r} created: {3} updated: {4}'.format( |
|
65 |
self.user_id, self.source, self.external_id, self.created, self.updated |
|
66 |
) |
|
62 |
return '<UserExternalId user: {!r} source: {!r} ' 'external_id: {!r} created: {} updated: {}'.format( |
|
63 |
self.user_id, self.source, self.external_id, self.created, self.updated |
|
67 | 64 |
) |
68 | 65 | |
69 | 66 |
class Meta: |
... | ... | |
356 | 353 |
if self.user_id and not self.user.has_usable_password(): |
357 | 354 |
self.user.set_password(uuid.uuid4().hex) |
358 | 355 |
self.user.save() |
359 |
return super(PasswordReset, self).save(*args, **kwargs)
|
|
356 |
return super().save(*args, **kwargs) |
|
360 | 357 | |
361 | 358 |
class Meta: |
362 | 359 |
verbose_name = _('password reset') |
src/authentic2/nonce/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/passwords.py | ||
---|---|---|
49 | 49 |
return ''.join(new_password) |
50 | 50 | |
51 | 51 | |
52 |
class PasswordChecker(object, metaclass=abc.ABCMeta):
|
|
53 |
class Check(object):
|
|
52 |
class PasswordChecker(metaclass=abc.ABCMeta): |
|
53 |
class Check: |
|
54 | 54 |
def __init__(self, label, result): |
55 | 55 |
self.label = label |
56 | 56 |
self.result = result |
... | ... | |
123 | 123 |
password_checker = get_password_checker() |
124 | 124 |
criteria = [check.label for check in password_checker(password) if not (only_errors and check.result)] |
125 | 125 |
if criteria: |
126 |
html_criteria = [u'<span class="a2-password-policy-rule">%s</span>' % criter for criter in criteria]
|
|
126 |
html_criteria = ['<span class="a2-password-policy-rule">%s</span>' % criter for criter in criteria] |
|
127 | 127 |
return _( |
128 | 128 |
'In order to create a secure password, please use at least: ' |
129 | 129 |
'<span class="a2-password-policy-container">%s</span>' |
src/authentic2/saml/admin.py | ||
---|---|---|
52 | 52 |
class TextAndFileWidget(forms.widgets.MultiWidget): |
53 | 53 |
def __init__(self, attrs=None): |
54 | 54 |
widgets = (forms.widgets.Textarea(), forms.widgets.FileInput()) |
55 |
super(TextAndFileWidget, self).__init__(widgets, attrs)
|
|
55 |
super().__init__(widgets, attrs) |
|
56 | 56 | |
57 | 57 |
def decompress(self, value): |
58 | 58 |
return (value, None) |
... | ... | |
73 | 73 |
attrs = {} |
74 | 74 |
if isinstance(value, (str, str)): |
75 | 75 |
attrs['rows'] = value.count('\n') + 5 |
76 |
attrs['cols'] = min(max((len(x) for x in value.split('\n'))), 150)
|
|
77 |
return super(TextAndFileWidget, self).render(name, value, attrs, **kwargs)
|
|
76 |
attrs['cols'] = min(max(len(x) for x in value.split('\n')), 150)
|
|
77 |
return super().render(name, value, attrs, **kwargs) |
|
78 | 78 | |
79 | 79 | |
80 | 80 |
class LibertyProviderForm(ModelForm): |
... | ... | |
114 | 114 |
class SAMLAttributeInlineForm(forms.ModelForm): |
115 | 115 |
def __init__(self, *args, **kwargs): |
116 | 116 |
service = kwargs.pop('service', None) |
117 |
super(SAMLAttributeInlineForm, self).__init__(*args, **kwargs)
|
|
117 |
super().__init__(*args, **kwargs) |
|
118 | 118 |
choices = list(get_service_attributes(service)) |
119 | 119 |
choices += [('edupersontargetedid', 'eduPersonTargetedId')] |
120 | 120 |
self.fields['attribute_name'].choices = choices |
... | ... | |
140 | 140 |
class NewForm(self.form): |
141 | 141 |
def __init__(self, *args, **kwargs): |
142 | 142 |
kwargs['service'] = obj |
143 |
super(NewForm, self).__init__(*args, **kwargs)
|
|
143 |
super().__init__(*args, **kwargs) |
|
144 | 144 | |
145 | 145 |
kwargs['form'] = NewForm |
146 |
return super(SAMLAttributeInlineAdmin, self).get_formset(request, obj=obj, **kwargs)
|
|
146 |
return super().get_formset(request, obj=obj, **kwargs) |
|
147 | 147 | |
148 | 148 | |
149 | 149 |
class LibertyProviderAdmin(admin.ModelAdmin): |
... | ... | |
167 | 167 |
) |
168 | 168 | |
169 | 169 |
def get_urls(self): |
170 |
urls = super(LibertyProviderAdmin, self).get_urls()
|
|
170 |
urls = super().get_urls() |
|
171 | 171 |
urls = [ |
172 | 172 |
url( |
173 | 173 |
r'^add-from-url/$', |
src/authentic2/saml/admin_views.py | ||
---|---|---|
20 | 20 |
from .forms import AddLibertyProviderFromUrlForm |
21 | 21 | |
22 | 22 | |
23 |
class AdminAddFormViewMixin(object):
|
|
23 |
class AdminAddFormViewMixin: |
|
24 | 24 |
model_admin = None |
25 | 25 | |
26 | 26 |
def get_context_data(self, **kwargs): |
27 |
ctx = super(AdminAddFormViewMixin, self).get_context_data(**kwargs)
|
|
27 |
ctx = super().get_context_data(**kwargs) |
|
28 | 28 |
ctx.update( |
29 | 29 |
{ |
30 | 30 |
'app_label': self.model_admin.model._meta.app_label, |
... | ... | |
40 | 40 |
template_name = 'admin/saml/libertyprovider/add_from_url.html' |
41 | 41 | |
42 | 42 |
def get_form_kwargs(self, **kwargs): |
43 |
kwargs = super(AddLibertyProviderFromUrlView, self).get_form_kwargs(**kwargs)
|
|
43 |
kwargs = super().get_form_kwargs(**kwargs) |
|
44 | 44 |
if 'entity_id' in self.request.GET: |
45 | 45 |
initial = kwargs.setdefault('initial', {}) |
46 | 46 |
initial['url'] = self.request.GET['entity_id'] |
... | ... | |
49 | 49 |
def form_valid(self, form): |
50 | 50 |
form.save() |
51 | 51 |
self.success_url = reverse('admin:saml_libertyprovider_change', args=(form.instance.id,)) |
52 |
return super(AddLibertyProviderFromUrlView, self).form_valid(form) |
|
52 |
return super().form_valid(form) |
src/authentic2/saml/app_settings.py | ||
---|---|---|
21 | 21 |
from django.utils.translation import ugettext_lazy as _ |
22 | 22 | |
23 | 23 | |
24 |
class AppSettings(object):
|
|
24 |
class AppSettings: |
|
25 | 25 |
__PREFIX = 'SAML_' |
26 | 26 |
__NAMES = ('ALLOWED_FEDERATION_MODE', 'DEFAULT_FEDERATION_MODE') |
27 | 27 |
src/authentic2/saml/fields.py | ||
---|---|---|
123 | 123 | |
124 | 124 |
def __init__(self, *args, **kwargs): |
125 | 125 |
self.max_choices = kwargs.pop('max_choices', 0) |
126 |
super(MultiSelectFormField, self).__init__(*args, **kwargs)
|
|
126 |
super().__init__(*args, **kwargs) |
|
127 | 127 | |
128 | 128 |
def clean(self, value): |
129 | 129 |
if not value and self.required: |
... | ... | |
168 | 168 |
def validate(self, value, model_instance): |
169 | 169 |
out = set() |
170 | 170 |
if self.choices: |
171 |
out |= set([option_key for option_key, _ in self.choices])
|
|
171 |
out |= {option_key for option_key, _ in self.choices}
|
|
172 | 172 |
out = set(value) - out |
173 | 173 |
if out: |
174 | 174 |
raise ValidationError(self.error_messages['invalid_choice'] % ','.join(list(out))) |
... | ... | |
193 | 193 |
return self.to_python(value) |
194 | 194 | |
195 | 195 |
def contribute_to_class(self, cls, name): |
196 |
super(MultiSelectField, self).contribute_to_class(cls, name)
|
|
196 |
super().contribute_to_class(cls, name) |
|
197 | 197 |
if self.choices: |
198 | 198 | |
199 | 199 |
def func(self, fieldname=name, choicedict=dict(self.choices)): |
src/authentic2/saml/forms.py | ||
---|---|---|
39 | 39 |
) |
40 | 40 | |
41 | 41 |
def clean(self): |
42 |
cleaned_data = super(AddLibertyProviderFromUrlForm, self).clean()
|
|
42 |
cleaned_data = super().clean() |
|
43 | 43 |
name = cleaned_data.get('name') |
44 | 44 |
slug = cleaned_data.get('slug') |
45 | 45 |
url = cleaned_data.get('url') |
src/authentic2/saml/lasso_helper.py | ||
---|---|---|
21 | 21 | |
22 | 22 | |
23 | 23 |
def lasso_elt(name): |
24 |
return '{{{0}}}{1}'.format(LASSO_NS, name)
|
|
24 |
return f'{{{LASSO_NS}}}{name}'
|
|
25 | 25 | |
26 | 26 | |
27 | 27 |
def samla_elt(name): |
28 |
return '{{{0}}}{1}'.format(SAML_ASSERTION_NS, name)
|
|
28 |
return f'{{{SAML_ASSERTION_NS}}}{name}'
|
|
29 | 29 | |
30 | 30 | |
31 | 31 |
SESSION_ELT = lasso_elt('Session') |
src/authentic2/saml/management/commands/sync-metadata.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import print_function |
|
18 | 17 | |
19 | 18 |
import io |
20 | 19 |
import os |
... | ... | |
345 | 344 |
try: |
346 | 345 |
with open(metadata_file_path, 'rb') as fd: |
347 | 346 |
metadata_file = io.BytesIO(fd.read()) |
348 |
except IOError:
|
|
347 |
except OSError:
|
|
349 | 348 |
raise CommandError('Unable to open file %s' % metadata_file_path) |
350 | 349 | |
351 | 350 |
try: |
src/authentic2/saml/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
import django.db.models.deletion |
5 | 2 |
from django.db import migrations, models |
6 | 3 | |
... | ... | |
696 | 693 |
), |
697 | 694 |
migrations.AlterUniqueTogether( |
698 | 695 |
name='samlattribute', |
699 |
unique_together=set(
|
|
700 |
[('content_type', 'object_id', 'name_format', 'name', 'friendly_name', 'attribute_name')]
|
|
701 |
),
|
|
696 |
unique_together={
|
|
697 |
('content_type', 'object_id', 'name_format', 'name', 'friendly_name', 'attribute_name')
|
|
698 |
},
|
|
702 | 699 |
), |
703 | 700 |
migrations.AddField( |
704 | 701 |
model_name='libertyserviceprovider', |
src/authentic2/saml/migrations/0002_auto_20150320_1245.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/saml/migrations/0002_ease_federation_migration.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
from authentic2.saml.common import AUTHENTIC_SAME_ID_SENTINEL |
src/authentic2/saml/migrations/0003_merge.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/saml/migrations/0004_auto_20150410_1438.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
import django.db.models.deletion |
5 | 2 |
from django.conf import settings |
6 | 3 |
from django.db import migrations, models |
src/authentic2/saml/migrations/0005_make_liberty_provider_inherit_from_service.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/saml/migrations/0006_restore_foreign_keys.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/saml/migrations/0007_copy_service_ptr_id_to_old_id.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/saml/migrations/0008_alter_foreign_keys.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/saml/migrations/0009_auto.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/saml/migrations/0010_auto.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/saml/migrations/0011_auto.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/saml/migrations/0012_auto_20150526_2239.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/saml/migrations/0013_auto_20150617_1004.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/saml/migrations/0014_auto_20150617_1216.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 | |
... | ... | |
13 | 10 |
operations = [ |
14 | 11 |
migrations.AlterUniqueTogether( |
15 | 12 |
name='libertysessiondump', |
16 |
unique_together=set([('django_session_key', 'kind')]),
|
|
13 |
unique_together={('django_session_key', 'kind')},
|
|
17 | 14 |
), |
18 | 15 |
] |
src/authentic2/saml/migrations/0015_auto_20150915_2032.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
import authentic2.saml.fields |
src/authentic2/saml/migrations/0016_auto_20150915_2041.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/saml/migrations/0017_auto_20170710_1738.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2/saml/models.py | ||
---|---|---|
172 | 172 | |
173 | 173 |
NAME_ID_FORMATS_CHOICES = [(force_text(x), y['caption']) for x, y in NAME_ID_FORMATS.items()] |
174 | 174 | |
175 |
ACCEPTED_NAME_ID_FORMAT_LENGTH = sum([len(x) for x, y in NAME_ID_FORMATS.items()]) + len(NAME_ID_FORMATS) - 1
|
|
175 |
ACCEPTED_NAME_ID_FORMAT_LENGTH = sum(len(x) for x, y in NAME_ID_FORMATS.items()) + len(NAME_ID_FORMATS) - 1
|
|
176 | 176 | |
177 | 177 | |
178 | 178 |
def saml2_urn_to_nidformat(urn, accepted=()): |
... | ... | |
328 | 328 |
enabled = models.BooleanField(verbose_name=_('enabled'), default=True, blank=True) |
329 | 329 | |
330 | 330 |
def clean(self): |
331 |
super(SAMLAttribute, self).clean()
|
|
331 |
super().clean() |
|
332 | 332 |
if self.attribute_name and not self.name: |
333 | 333 |
self.name = self.attribute_name |
334 | 334 | |
... | ... | |
401 | 401 |
'''Update the SHA1 hash of the entity_id when saving''' |
402 | 402 |
if self.protocol_conformance == 3: |
403 | 403 |
self.entity_id_sha1 = hashlib.sha1(self.entity_id.encode('ascii')).hexdigest() |
404 |
super(LibertyProvider, self).save(*args, **kwargs)
|
|
404 |
super().save(*args, **kwargs) |
|
405 | 405 | |
406 | 406 |
def clean(self): |
407 |
super(LibertyProvider, self).clean()
|
|
407 |
super().clean() |
|
408 | 408 |
p = lasso.Provider.newFromBuffer(lasso.PROVIDER_ROLE_ANY, force_text(self.metadata.encode('utf8'))) |
409 | 409 |
if p is None: |
410 | 410 |
raise ValidationError(_('Invalid metadata file')) |
src/authentic2/saml/saml2utils.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import print_function |
|
18 | 17 | |
19 | 18 |
import collections |
20 | 19 |
import datetime |
... | ... | |
115 | 114 |
return etree.TreeBuilder.end(self, tag) |
116 | 115 | |
117 | 116 | |
118 |
class Saml2Metadata(object):
|
|
117 |
class Saml2Metadata: |
|
119 | 118 |
ENTITY_DESCRIPTOR = 'EntityDescriptor' |
120 | 119 |
SP_SSO_DESCRIPTOR = 'SPSSODescriptor' |
121 | 120 |
IDP_SSO_DESCRIPTOR = 'IDPSSODescriptor' |
src/authentic2/saml/shibboleth/afp_parser.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import print_function |
|
18 | 17 | |
19 | 18 |
import xml.etree.ElementTree as ET |
20 | 19 | |
21 | 20 |
from authentic2.saml.shibboleth.utils import FancyTreeBuilder |
22 | 21 | |
23 | 22 | |
24 |
class NS(object):
|
|
23 |
class NS: |
|
25 | 24 |
AFP = 'urn:mace:shibboleth:2.0:afp' |
26 | 25 |
BASIC = 'urn:mace:shibboleth:2.0:afp:mf:basic' |
27 | 26 |
SAML = 'urn:mace:shibboleth:2.0:afp:mf:saml' |
src/authentic2/saml/shibboleth/utils.py | ||
---|---|---|
21 | 21 |
"""Attach defined namespaces to elements during parsing""" |
22 | 22 | |
23 | 23 |
def __init__(self, *args, **kwargs): |
24 |
super(FancyTreeBuilder, self).__init__(*args, **kwargs)
|
|
24 |
super().__init__(*args, **kwargs) |
|
25 | 25 |
self._namespaces = {} |
26 | 26 |
self._parser.StartNamespaceDeclHandler = self._start_ns |
27 | 27 | |
28 | 28 |
def _start(self, *args): |
29 |
elem = super(FancyTreeBuilder, self)._start(*args)
|
|
29 |
elem = super()._start(*args) |
|
30 | 30 |
elem.namespaces = self._namespaces.copy() |
31 | 31 |
return elem |
32 | 32 | |
33 | 33 |
def _start_list(self, *args): |
34 |
elem = super(FancyTreeBuilder, self)._start_list(*args)
|
|
34 |
elem = super()._start_list(*args) |
|
35 | 35 |
elem.namespaces = self._namespaces.copy() |
36 | 36 |
return elem |
37 | 37 |
src/authentic2/serializers.py | ||
---|---|---|
44 | 44 |
del self._current[pfield.ct_field] |
45 | 45 |
del self._current[pfield.fk_field] |
46 | 46 |
self._current[pfield.name] = (ct.natural_key(), sub_obj.natural_key()) |
47 |
super(Serializer, self).end_object(obj)
|
|
47 |
super().end_object(obj) |
|
48 | 48 | |
49 | 49 | |
50 | 50 |
def PreDeserializer(objects, **options): |
... | ... | |
79 | 79 |
try: |
80 | 80 |
objects = json.loads(stream_or_string) |
81 | 81 |
objects = PreDeserializer(objects, **options) |
82 |
for obj in PythonDeserializer(objects, **options): |
|
83 |
yield obj |
|
82 |
yield from PythonDeserializer(objects, **options) |
|
84 | 83 |
except GeneratorExit: |
85 | 84 |
raise |
86 | 85 |
except Exception as e: |
src/authentic2/user_login_failure.py | ||
---|---|---|
35 | 35 |
cache.add(key(identifier), 0) |
36 | 36 |
count = cache.incr(key(identifier)) |
37 | 37 |
logger = logging.getLogger('authentic2.user_login_failure') |
38 |
logger.info(u'user %s failed to login', identifier)
|
|
38 |
logger.info('user %s failed to login', identifier) |
|
39 | 39 |
if ( |
40 | 40 |
app_settings.A2_LOGIN_FAILURE_COUNT_BEFORE_WARNING |
41 | 41 |
and count >= app_settings.A2_LOGIN_FAILURE_COUNT_BEFORE_WARNING |
42 | 42 |
): |
43 |
logger.warning(u'user %s failed to login more than %d times in a row', identifier, count) |
|
43 |
logger.warning('user %s failed to login more than %d times in a row', identifier, count) |
src/authentic2/utils/__init__.py | ||
---|---|---|
65 | 65 |
return True |
66 | 66 | |
67 | 67 | |
68 |
class MWT(object):
|
|
68 |
class MWT: |
|
69 | 69 |
"""Memoize With Timeout""" |
70 | 70 | |
71 | 71 |
_caches = {} |
... | ... | |
117 | 117 |
get_session_store()(session_key=django_session_key).flush() |
118 | 118 | |
119 | 119 | |
120 |
class IterableFactory(object):
|
|
120 |
class IterableFactory: |
|
121 | 121 |
"""Return an new iterable using a generator function each time this object |
122 | 122 |
is iterated.""" |
123 | 123 | |
... | ... | |
251 | 251 |
return user.username |
252 | 252 | |
253 | 253 | |
254 |
class Service(object):
|
|
254 |
class Service: |
|
255 | 255 |
url = None |
256 | 256 |
name = None |
257 | 257 |
actions = [] |
... | ... | |
833 | 833 |
legacy_body_templates=['registration/activation_email.txt'], |
834 | 834 |
legacy_html_body_templates=['registration/activation_email.html'], |
835 | 835 |
) |
836 |
logger.info(u'registration mail sent to %s with registration URL %s...', email, registration_url)
|
|
836 |
logger.info('registration mail sent to %s with registration URL %s...', email, registration_url) |
|
837 | 837 |
request.journal.record('user.registration.request', email=email) |
838 | 838 | |
839 | 839 | |
... | ... | |
852 | 852 |
} |
853 | 853 |
template_names = ['authentic2/account_deletion_code'] |
854 | 854 |
send_templated_mail(user, template_names, context, request=request, per_ou_templates=True) |
855 |
logger.info(u'account deletion code sent to %s', user.email)
|
|
855 |
logger.info('account deletion code sent to %s', user.email) |
|
856 | 856 | |
857 | 857 | |
858 | 858 |
def send_account_deletion_mail(request, user): |
... | ... | |
864 | 864 |
context = {'full_name': user.get_full_name(), 'user': user, 'site': request.get_host()} |
865 | 865 |
template_names = ['authentic2/account_delete_notification'] |
866 | 866 |
send_templated_mail(user, template_names, context, request=request, per_ou_templates=True) |
867 |
logger.info(u'account deletion mail sent to %s', user.email)
|
|
867 |
logger.info('account deletion mail sent to %s', user.email) |
|
868 | 868 | |
869 | 869 | |
870 | 870 |
def build_reset_password_url(user, request=None, next_url=None, set_random_password=True, sign_next_url=True): |
... | ... | |
971 | 971 |
break |
972 | 972 |
if progress_callback: |
973 | 973 |
progress_callback(i * size) |
974 |
for row in chunk: |
|
975 |
yield row |
|
974 |
yield from chunk |
|
976 | 975 | |
977 | 976 | |
978 | 977 |
def lower_keys(d): |
979 | 978 |
'''Convert all keys in dictionary d to lowercase''' |
980 |
return dict((key.lower(), value) for key, value in d.items())
|
|
979 |
return {key.lower(): value for key, value in d.items()}
|
|
981 | 980 | |
982 | 981 | |
983 | 982 |
def to_dict_of_set(d): |
984 | 983 |
'''Convert a dictionary of sequence into a dictionary of sets''' |
985 |
return dict((k, set(v)) for k, v in d.items())
|
|
984 |
return {k: set(v) for k, v in d.items()}
|
|
986 | 985 | |
987 | 986 | |
988 | 987 |
def datetime_to_utc(dt): |
... | ... | |
1186 | 1185 |
'user_pk': user.pk, |
1187 | 1186 |
} |
1188 | 1187 |
) |
1189 |
link = '{0}?token={1}'.format(reverse('email-change-verify'), token)
|
|
1188 |
link = '{}?token={}'.format(reverse('email-change-verify'), token)
|
|
1190 | 1189 |
link = request.build_absolute_uri(link) |
1191 | 1190 | |
1192 | 1191 |
# check if email should be unique and is not |
... | ... | |
1210 | 1209 |
'email_is_not_unique': email_is_not_unique, |
1211 | 1210 |
} |
1212 | 1211 |
) |
1213 |
logger.info(u'sent email verify email to %s for %s', email, user)
|
|
1212 |
logger.info('sent email verify email to %s for %s', email, user) |
|
1214 | 1213 |
send_templated_mail( |
1215 | 1214 |
email, |
1216 | 1215 |
template_names, |
src/authentic2/utils/evaluate.py | ||
---|---|---|
52 | 52 |
text = None |
53 | 53 | |
54 | 54 |
def __init__(self, message, code=None, params=None, node=None, column=None, text=None): |
55 |
super(ExpressionError, self).__init__(message, code=code, params=params)
|
|
55 |
super().__init__(message, code=code, params=params) |
|
56 | 56 |
if hasattr(node, 'col_offset'): |
57 | 57 |
self.set_node(node) |
58 | 58 |
if column is not None: |
... | ... | |
103 | 103 | |
104 | 104 |
# now recurse on subnodes |
105 | 105 |
try: |
106 |
return super(BaseExpressionValidator, self).generic_visit(node)
|
|
106 |
return super().generic_visit(node) |
|
107 | 107 |
except ExpressionError as e: |
108 | 108 |
# for errors in non expr nodes (so without a col_offset attribute, |
109 | 109 |
# set the nearer expr node as the node of the error |
... | ... | |
175 | 175 |
] |
176 | 176 | |
177 | 177 |
def __init__(self, authorized_nodes=None, forbidden_nodes=None): |
178 |
super(ConditionValidator, self).__init__( |
|
179 |
authorized_nodes=authorized_nodes, forbidden_nodes=forbidden_nodes |
|
180 |
) |
|
178 |
super().__init__(authorized_nodes=authorized_nodes, forbidden_nodes=forbidden_nodes) |
|
181 | 179 |
self.authorized_nodes.append(ast.NameConstant) |
182 | 180 | |
183 | 181 |
def check_Name(self, node): |
src/authentic2/utils/lazy.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import unicode_literals |
|
18 | 17 | |
19 | 18 |
from django.utils.encoding import force_text |
20 | 19 |
from django.utils.functional import keep_lazy |
src/authentic2/utils/lookups.py | ||
---|---|---|
14 | 14 |
""" |
15 | 15 | |
16 | 16 |
def as_postgresql(self, compiler, connection): |
17 |
return super(ConcatPair, self).as_sql( |
|
18 |
compiler, connection, template='%(expressions)s', arg_joiner=' || ' |
|
19 |
) |
|
17 |
return super().as_sql(compiler, connection, template='%(expressions)s', arg_joiner=' || ') |
|
20 | 18 | |
21 | 19 | |
22 | 20 |
class ImmutableConcat(Concat): |
src/authentic2/utils/template.py | ||
---|---|---|
23 | 23 |
pass |
24 | 24 | |
25 | 25 | |
26 |
class Template(object):
|
|
26 |
class Template: |
|
27 | 27 |
def __init__(self, value, raises=False): |
28 | 28 |
self.value = value |
29 | 29 |
self.raises = raises |
src/authentic2/validators.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import unicode_literals |
|
18 | 17 | |
19 | 18 |
import re |
20 | 19 |
import smtplib |
... | ... | |
34 | 33 | |
35 | 34 | |
36 | 35 |
# copied from http://www.djangotips.com/real-email-validation |
37 |
class EmailValidator(object):
|
|
36 |
class EmailValidator: |
|
38 | 37 |
def __init__(self, rcpt_check=False): |
39 | 38 |
self.rcpt_check = rcpt_check |
40 | 39 | |
... | ... | |
103 | 102 |
class UsernameValidator(RegexValidator): |
104 | 103 |
def __init__(self, *args, **kwargs): |
105 | 104 |
self.regex = app_settings.A2_REGISTRATION_FORM_USERNAME_REGEX |
106 |
super(UsernameValidator, self).__init__(*args, **kwargs)
|
|
105 |
super().__init__(*args, **kwargs) |
|
107 | 106 | |
108 | 107 | |
109 | 108 |
@deconstructible |
src/authentic2/views.py | ||
---|---|---|
130 | 130 |
return self.request.user |
131 | 131 | |
132 | 132 |
def get_form_kwargs(self, **kwargs): |
133 |
kwargs = super(EditProfile, self).get_form_kwargs(**kwargs)
|
|
133 |
kwargs = super().get_form_kwargs(**kwargs) |
|
134 | 134 |
kwargs['next_url'] = utils.select_next_url(self.request, reverse('account_management')) |
135 | 135 |
return kwargs |
136 | 136 | |
... | ... | |
142 | 142 |
def post(self, request, *args, **kwargs): |
143 | 143 |
if 'cancel' in request.POST: |
144 | 144 |
return utils.redirect(request, self.get_success_url()) |
145 |
return super(EditProfile, self).post(request, *args, **kwargs)
|
|
145 |
return super().post(request, *args, **kwargs) |
|
146 | 146 | |
147 | 147 |
def form_valid(self, form): |
148 |
response = super(EditProfile, self).form_valid(form)
|
|
148 |
response = super().form_valid(form) |
|
149 | 149 |
hooks.call_hooks('event', name='edit-profile', user=self.request.user, form=form) |
150 | 150 |
self.request.journal.record('user.profile.edit', form=form) |
151 | 151 |
return response |
... | ... | |
167 | 167 |
return profile_forms.EmailChangeFormNoPassword |
168 | 168 | |
169 | 169 |
def get_form_kwargs(self): |
170 |
kwargs = super(EmailChangeView, self).get_form_kwargs()
|
|
170 |
kwargs = super().get_form_kwargs() |
|
171 | 171 |
kwargs['user'] = self.request.user |
172 | 172 |
return kwargs |
173 | 173 | |
174 | 174 |
def post(self, request, *args, **kwargs): |
175 | 175 |
if 'cancel' in request.POST: |
176 | 176 |
return utils.redirect(request, 'account_management') |
177 |
return super(EmailChangeView, self).post(request, *args, **kwargs)
|
|
177 |
return super().post(request, *args, **kwargs) |
|
178 | 178 | |
179 | 179 |
def form_valid(self, form): |
180 | 180 |
email = form.cleaned_data['email'] |
... | ... | |
193 | 193 |
self.request.journal.record( |
194 | 194 |
'user.email.change.request', user=self.request.user, session=self.request.session, new_email=email |
195 | 195 |
) |
196 |
return super(EmailChangeView, self).form_valid(form)
|
|
196 |
return super().form_valid(form) |
|
197 | 197 | |
198 | 198 | |
199 | 199 |
email_change = decorators.setting_enabled('A2_PROFILE_CAN_CHANGE_EMAIL')( |
... | ... | |
392 | 392 |
def dispatch(self, request, *args, **kwargs): |
393 | 393 |
if app_settings.A2_HOMEPAGE_URL: |
394 | 394 |
return utils.redirect(request, app_settings.A2_HOMEPAGE_URL) |
395 |
return login_required(super(Homepage, self).dispatch)(request, *args, **kwargs)
|
|
395 |
return login_required(super().dispatch)(request, *args, **kwargs) |
|
396 | 396 | |
397 | 397 |
def get_context_data(self, **kwargs): |
398 |
ctx = super(Homepage, self).get_context_data(**kwargs)
|
|
398 |
ctx = super().get_context_data(**kwargs) |
|
399 | 399 |
ctx['account_management'] = 'account_management' |
400 | 400 |
ctx['authorized_services'] = service_list(self.request) |
401 | 401 |
return ctx |
... | ... | |
411 | 411 |
def dispatch(self, request, *args, **kwargs): |
412 | 412 |
if app_settings.A2_ACCOUNTS_URL: |
413 | 413 |
return utils.redirect(request, app_settings.A2_ACCOUNTS_URL) |
414 |
return super(ProfileView, self).dispatch(request, *args, **kwargs)
|
|
414 |
return super().dispatch(request, *args, **kwargs) |
|
415 | 415 | |
416 | 416 |
def get_context_data(self, **kwargs): |
417 |
context = super(ProfileView, self).get_context_data(**kwargs)
|
|
417 |
context = super().get_context_data(**kwargs) |
|
418 | 418 |
frontends = utils.get_backends('AUTH_FRONTENDS') |
419 | 419 | |
420 | 420 |
request = self.request |
... | ... | |
577 | 577 |
# Get redirection targets for full logout with redirections |
578 | 578 |
# (needed before local logout) |
579 | 579 |
targets = redirect_logout_list(request) |
580 |
logger.debug('Accumulated redirections : {}'.format(targets))
|
|
580 |
logger.debug(f'Accumulated redirections : {targets}')
|
|
581 | 581 |
# Local logout |
582 | 582 |
request.journal.record('user.logout') |
583 | 583 |
auth_logout(request) |
... | ... | |
587 | 587 |
targets.append(next_url) |
588 | 588 |
# Put redirection targets in session (after local logout) |
589 | 589 |
request.session['logout_redirections'] = targets |
590 |
logger.debug('All planned redirections : {}'.format(targets))
|
|
590 |
logger.debug(f'All planned redirections : {targets}')
|
|
591 | 591 |
# Full logout by redirections if any |
592 | 592 |
targets = request.session.pop('logout_redirections', None) |
593 | 593 |
if targets: |
594 | 594 |
# Full logout with redirections |
595 |
logger.debug('Redirections queue: {}'.format(targets))
|
|
595 |
logger.debug(f'Redirections queue: {targets}')
|
|
596 | 596 |
next_url = targets.pop(0) |
597 | 597 |
request.session['logout_redirections'] = targets |
598 |
logger.debug('Next redirection : {}'.format(next_url))
|
|
598 |
logger.debug(f'Next redirection : {next_url}')
|
|
599 | 599 |
response = shortcuts.redirect(next_url) |
600 | 600 |
if local_logout_done: |
601 | 601 |
response.set_cookie('a2_just_logged_out', 1, max_age=60) |
... | ... | |
622 | 622 |
class LoggedInView(View): |
623 | 623 |
'''JSONP web service to detect if an user is logged''' |
624 | 624 | |
625 |
http_method_names = [u'get']
|
|
625 |
http_method_names = ['get'] |
|
626 | 626 | |
627 | 627 |
def check_referrer(self): |
628 | 628 |
'''Check if the given referer is authorized''' |
... | ... | |
636 | 636 |
if not self.check_referrer(): |
637 | 637 |
return HttpResponseForbidden() |
638 | 638 |
callback = request.GET.get('callback') |
639 |
content = '{0}({1})'.format(callback, int(request.user.is_authenticated))
|
|
639 |
content = f'{callback}({int(request.user.is_authenticated)})'
|
|
640 | 640 |
return HttpResponse(content, content_type='application/json') |
641 | 641 | |
642 | 642 | |
... | ... | |
664 | 664 |
] |
665 | 665 | |
666 | 666 |
def get_form_kwargs(self, **kwargs): |
667 |
kwargs = super(PasswordResetView, self).get_form_kwargs(**kwargs)
|
|
667 |
kwargs = super().get_form_kwargs(**kwargs) |
|
668 | 668 |
initial = kwargs.setdefault('initial', {}) |
669 | 669 |
initial['next_url'] = utils.select_next_url(self.request, '') |
670 | 670 |
return kwargs |
671 | 671 | |
672 | 672 |
def get_context_data(self, **kwargs): |
673 |
ctx = super(PasswordResetView, self).get_context_data(**kwargs)
|
|
673 |
ctx = super().get_context_data(**kwargs) |
|
674 | 674 |
if app_settings.A2_USER_CAN_RESET_PASSWORD is False: |
675 | 675 |
raise Http404('Password reset is not allowed.') |
676 | 676 |
ctx['title'] = _('Password reset') |
... | ... | |
740 | 740 | |
741 | 741 |
form.save() |
742 | 742 |
self.request.session['reset_email'] = email |
743 |
return super(PasswordResetView, self).form_valid(form)
|
|
743 |
return super().form_valid(form) |
|
744 | 744 | |
745 | 745 | |
746 | 746 |
password_reset = PasswordResetView.as_view() |
... | ... | |
750 | 750 |
template_name = 'registration/password_reset_instructions.html' |
751 | 751 | |
752 | 752 |
def get_context_data(self, **kwargs): |
753 |
ctx = super(PasswordResetInstructionsView, self).get_context_data(**kwargs)
|
|
753 |
ctx = super().get_context_data(**kwargs) |
|
754 | 754 |
ctx['from_email_address'] = parseaddr(settings.DEFAULT_FROM_EMAIL)[1] |
755 | 755 |
return ctx |
756 | 756 | |
... | ... | |
803 | 803 |
request, _('It\'s not possible to reset your password. Please contact an administrator.') |
804 | 804 |
) |
805 | 805 |
return utils.redirect(request, self.get_success_url()) |
806 |
return super(PasswordResetConfirmView, self).dispatch(request, *args, **kwargs)
|
|
806 |
return super().dispatch(request, *args, **kwargs) |
|
807 | 807 | |
808 | 808 |
def get_context_data(self, **kwargs): |
809 |
ctx = super(PasswordResetConfirmView, self).get_context_data(**kwargs)
|
|
809 |
ctx = super().get_context_data(**kwargs) |
|
810 | 810 |
# compatibility with existing templates ! |
811 | 811 |
ctx['title'] = _('Enter new password') |
812 | 812 |
ctx['validlink'] = True |
813 | 813 |
return ctx |
814 | 814 | |
815 | 815 |
def get_form_kwargs(self): |
816 |
kwargs = super(PasswordResetConfirmView, self).get_form_kwargs()
|
|
816 |
kwargs = super().get_form_kwargs() |
|
817 | 817 |
kwargs['user'] = self.user |
818 | 818 |
return kwargs |
819 | 819 | |
... | ... | |
822 | 822 |
form.user.email_verified = True |
823 | 823 |
form.save() |
824 | 824 |
hooks.call_hooks('event', name='password-reset-confirm', user=form.user, token=self.token, form=form) |
825 |
logger.info(u'password reset for user %s with token %r', self.user, self.token.uuid)
|
|
825 |
logger.info('password reset for user %s with token %r', self.user, self.token.uuid) |
|
826 | 826 |
self.token.delete() |
827 | 827 |
return self.finish() |
828 | 828 | |
... | ... | |
853 | 853 |
request.GET.get('token'), max_age=settings.ACCOUNT_ACTIVATION_DAYS * 3600 * 24 |
854 | 854 |
) |
855 | 855 |
except (TypeError, ValueError, signing.BadSignature) as e: |
856 |
logger.warning(u'registration_view: invalid token: %s', e)
|
|
856 |
logger.warning('registration_view: invalid token: %s', e) |
|
857 | 857 |
return HttpResponseBadRequest('invalid token', content_type='text/plain') |
858 | 858 |
if 'ou' in self.token: |
859 | 859 |
self.ou = OU.objects.get(pk=self.token['ou']) |
860 | 860 |
self.next_url = self.token.pop(REDIRECT_FIELD_NAME, utils.select_next_url(request, None)) |
861 |
return super(BaseRegistrationView, self).dispatch(request, *args, **kwargs)
|
|
861 |
return super().dispatch(request, *args, **kwargs) |
|
862 | 862 | |
863 | 863 |
def form_valid(self, form): |
864 | 864 |
if form.is_robot(): |
... | ... | |
939 | 939 |
) |
940 | 940 | |
941 | 941 |
def get_context_data(self, **kwargs): |
942 |
context = super(BaseRegistrationView, self).get_context_data(**kwargs)
|
|
942 |
context = super().get_context_data(**kwargs) |
|
943 | 943 |
parameters = {'request': self.request, 'context': context} |
944 | 944 |
blocks = [ |
945 | 945 |
utils.get_authenticator_method(authenticator, 'registration', parameters) |
... | ... | |
1012 | 1012 |
self.init_fields_labels_and_help_texts() |
1013 | 1013 |
# if registration is done during an SSO add the service to the registration event |
1014 | 1014 |
self.service = get_service_from_token(self.token) |
1015 |
return super(RegistrationCompletionView, self).dispatch(request, *args, **kwargs)
|
|
1015 |
return super().dispatch(request, *args, **kwargs) |
|
1016 | 1016 | |
1017 | 1017 |
def init_fields_labels_and_help_texts(self): |
1018 | 1018 |
attributes = models.Attribute.objects.filter(asked_on_registration=True) |
... | ... | |
1070 | 1070 | |
1071 | 1071 |
def get_form_kwargs(self, **kwargs): |
1072 | 1072 |
'''Initialize mail from token''' |
1073 |
kwargs = super(RegistrationCompletionView, self).get_form_kwargs(**kwargs)
|
|
1073 |
kwargs = super().get_form_kwargs(**kwargs) |
|
1074 | 1074 |
if 'ou' in self.token: |
1075 | 1075 |
ou = get_object_or_404(OU, id=self.token['ou']) |
1076 | 1076 |
else: |
... | ... | |
1080 | 1080 |
for key in self.token: |
1081 | 1081 |
if key in app_settings.A2_PRE_REGISTRATION_FIELDS: |
1082 | 1082 |
attributes[key] = self.token[key] |
1083 |
logger.debug(u'attributes %s', attributes)
|
|
1083 |
logger.debug('attributes %s', attributes) |
|
1084 | 1084 | |
1085 | 1085 |
prefilling_list = utils.accumulate_from_backends(self.request, 'registration_form_prefill') |
1086 |
logger.debug(u'prefilling_list %s', prefilling_list)
|
|
1086 |
logger.debug('prefilling_list %s', prefilling_list) |
|
1087 | 1087 |
# Build a single meaningful prefilling with sets of values |
1088 | 1088 |
prefilling = {} |
1089 | 1089 |
for p in prefilling_list: |
1090 | 1090 |
for name, values in p.items(): |
1091 | 1091 |
if name in self.fields: |
1092 | 1092 |
prefilling.setdefault(name, set()).update(values) |
1093 |
logger.debug(u'prefilling %s', prefilling)
|
|
1093 |
logger.debug('prefilling %s', prefilling) |
|
1094 | 1094 | |
1095 | 1095 |
for name, values in prefilling.items(): |
1096 | 1096 |
attributes[name] = ' '.join(values) |
1097 |
logger.debug(u'attributes with prefilling %s', attributes)
|
|
1097 |
logger.debug('attributes with prefilling %s', attributes) |
|
1098 | 1098 | |
1099 | 1099 |
if self.token.get('user_id'): |
1100 | 1100 |
kwargs['instance'] = User.objects.get(id=self.token.get('user_id')) |
... | ... | |
1108 | 1108 |
return kwargs |
1109 | 1109 | |
1110 | 1110 |
def get_form(self, form_class=None): |
1111 |
form = super(RegistrationCompletionView, self).get_form(form_class=form_class)
|
|
1111 |
form = super().get_form(form_class=form_class) |
|
1112 | 1112 |
hooks.call_hooks('front_modify_form', self, form) |
1113 | 1113 |
return form |
1114 | 1114 | |
1115 | 1115 |
def get_context_data(self, **kwargs): |
1116 |
ctx = super(RegistrationCompletionView, self).get_context_data(**kwargs)
|
|
1116 |
ctx = super().get_context_data(**kwargs) |
|
1117 | 1117 |
ctx['token'] = self.token |
1118 | 1118 |
ctx['users'] = self.users |
1119 | 1119 |
ctx['email'] = self.email |
... | ... | |
1151 | 1151 |
user = form.save() |
1152 | 1152 |
return self.registration_success(request, user, form) |
1153 | 1153 |
self.get_form = lambda *args, **kwargs: form |
1154 |
return super(RegistrationCompletionView, self).get(request, *args, **kwargs)
|
|
1154 |
return super().get(request, *args, **kwargs) |
|
1155 | 1155 | |
1156 | 1156 |
def post(self, request, *args, **kwargs): |
1157 | 1157 |
if self.users and self.email_is_unique: |
... | ... | |
1167 | 1167 |
request, user, method=self.authentication_method, service=self.service |
1168 | 1168 |
) |
1169 | 1169 |
return utils.redirect(request, self.get_success_url()) |
1170 |
return super(RegistrationCompletionView, self).post(request, *args, **kwargs)
|
|
1170 |
return super().post(request, *args, **kwargs) |
|
1171 | 1171 | |
1172 | 1172 |
def form_valid(self, form): |
1173 | 1173 | |
... | ... | |
1199 | 1199 |
self.token_obj.delete() |
1200 | 1200 |
self.request.session['registered_email'] = form.cleaned_data['email'] |
1201 | 1201 |
return utils.redirect(self.request, 'registration_complete') |
1202 |
super(RegistrationCompletionView, self).form_valid(form)
|
|
1202 |
super().form_valid(form) |
|
1203 | 1203 |
return self.registration_success(self.request, form.instance, form) |
1204 | 1204 | |
1205 | 1205 |
def registration_success(self, request, user, form): |
... | ... | |
1251 | 1251 |
def dispatch(self, request, *args, **kwargs): |
1252 | 1252 |
if not app_settings.A2_REGISTRATION_CAN_DELETE_ACCOUNT: |
1253 | 1253 |
return utils.redirect(request, '..') |
1254 |
return super(DeleteView, self).dispatch(request, *args, **kwargs)
|
|
1254 |
return super().dispatch(request, *args, **kwargs) |
|
1255 | 1255 | |
1256 | 1256 |
def post(self, request, *args, **kwargs): |
1257 | 1257 |
if 'cancel' in request.POST: |
... | ... | |
1261 | 1261 |
return utils.redirect(request, 'account_management') |
1262 | 1262 | |
1263 | 1263 |
def get_context_data(self, **kwargs): |
1264 |
ctx = super(DeleteView, self).get_context_data(**kwargs)
|
|
1264 |
ctx = super().get_context_data(**kwargs) |
|
1265 | 1265 |
ctx['email'] = self.request.user.email |
1266 | 1266 |
return ctx |
1267 | 1267 | |
... | ... | |
1293 | 1293 |
except get_user_model().DoesNotExist: |
1294 | 1294 |
error = _('This account has previously been deleted.') |
1295 | 1295 |
else: |
1296 |
return super(ValidateDeletionView, self).dispatch(request, *args, **kwargs)
|
|
1296 |
return super().dispatch(request, *args, **kwargs) |
|
1297 | 1297 |
messages.error(request, error) |
1298 | 1298 |
return utils.redirect(request, 'auth_homepage') |
1299 | 1299 | |
1300 | 1300 |
def post(self, request, *args, **kwargs): |
1301 | 1301 |
if 'cancel' not in request.POST: |
1302 | 1302 |
utils.send_account_deletion_mail(self.request, self.user) |
1303 |
logger.info(u'deletion of account %s performed', self.user)
|
|
1303 |
logger.info('deletion of account %s performed', self.user) |
|
1304 | 1304 |
hooks.call_hooks('event', name='delete-account', user=self.user) |
1305 | 1305 |
request.journal.record('user.deletion', user=self.user) |
1306 | 1306 |
is_deleted_user_logged = self.user == request.user |
... | ... | |
1314 | 1314 |
return utils.redirect(request, 'auth_homepage') |
1315 | 1315 | |
1316 | 1316 |
def get_context_data(self, **kwargs): |
1317 |
ctx = super(ValidateDeletionView, self).get_context_data(**kwargs)
|
|
1317 |
ctx = super().get_context_data(**kwargs) |
|
1318 | 1318 |
ctx['user'] = self.user # Not necessarily the user in request |
1319 | 1319 |
return ctx |
1320 | 1320 | |
... | ... | |
1326 | 1326 |
kwargs['next_url'] = utils.select_next_url(self.request, settings.LOGIN_REDIRECT_URL) |
1327 | 1327 |
kwargs['from_email'] = settings.DEFAULT_FROM_EMAIL |
1328 | 1328 |
kwargs['from_email_address'] = parseaddr(settings.DEFAULT_FROM_EMAIL)[1] |
1329 |
return super(RegistrationCompleteView, self).get_context_data( |
|
1330 |
account_activation_days=settings.ACCOUNT_ACTIVATION_DAYS, **kwargs |
|
1331 |
) |
|
1329 |
return super().get_context_data(account_activation_days=settings.ACCOUNT_ACTIVATION_DAYS, **kwargs) |
|
1332 | 1330 | |
1333 | 1331 | |
1334 | 1332 |
registration_complete = RegistrationCompleteView.as_view() |
... | ... | |
1348 | 1346 |
if not utils.user_can_change_password(request=request): |
1349 | 1347 |
messages.warning(request, _('Password change is forbidden')) |
1350 | 1348 |
return utils.redirect(request, self.post_change_redirect) |
1351 |
return super(PasswordChangeView, self).dispatch(request, *args, **kwargs)
|
|
1349 |
return super().dispatch(request, *args, **kwargs) |
|
1352 | 1350 | |
1353 | 1351 |
def post(self, request, *args, **kwargs): |
1354 | 1352 |
if 'cancel' in request.POST: |
1355 | 1353 |
return utils.redirect(request, self.post_change_redirect) |
1356 |
return super(PasswordChangeView, self).post(request, *args, **kwargs)
|
|
1354 |
return super().post(request, *args, **kwargs) |
|
1357 | 1355 | |
1358 | 1356 |
def form_valid(self, form): |
1359 | 1357 |
hooks.call_hooks('event', name='change-password', user=self.request.user, request=self.request) |
1360 | 1358 |
messages.info(self.request, _('Password changed')) |
1361 | 1359 |
models.PasswordReset.objects.filter(user=self.request.user).delete() |
1362 |
response = super(PasswordChangeView, self).form_valid(form)
|
|
1360 |
response = super().form_valid(form) |
|
1363 | 1361 |
self.request.journal.record('user.password.change', session=self.request.session) |
1364 | 1362 |
return response |
1365 | 1363 | |
... | ... | |
1370 | 1368 |
return passwords_forms.SetPasswordForm |
1371 | 1369 | |
1372 | 1370 |
def get_context_data(self, **kwargs): |
1373 |
ctx = super(PasswordChangeView, self).get_context_data(**kwargs)
|
|
1371 |
ctx = super().get_context_data(**kwargs) |
|
1374 | 1372 |
ctx[REDIRECT_FIELD_NAME] = self.post_change_redirect |
1375 | 1373 |
return ctx |
1376 | 1374 | |
... | ... | |
1401 | 1399 |
def get_context_data(self, **kwargs): |
1402 | 1400 |
from authentic2_idp_oidc.models import OIDCAuthorization |
1403 | 1401 | |
1404 |
context = super(AuthorizedOauthServicesView, self).get_context_data(**kwargs)
|
|
1402 |
context = super().get_context_data(**kwargs) |
|
1405 | 1403 |
context['authorized_oauth_services'] = OIDCAuthorization.objects.filter(user=self.request.user) |
1406 | 1404 |
return context |
1407 | 1405 |
src/authentic2_auth_fc/app_settings.py | ||
---|---|---|
17 | 17 |
import sys |
18 | 18 | |
19 | 19 | |
20 |
class AppSettings(object):
|
|
20 |
class AppSettings: |
|
21 | 21 |
__SENTINEL = object() |
22 | 22 | |
23 | 23 |
def __init__(self, prefix): |
src/authentic2_auth_fc/apps.py | ||
---|---|---|
20 | 20 |
from . import app_settings |
21 | 21 | |
22 | 22 | |
23 |
class Plugin(object):
|
|
23 |
class Plugin: |
|
24 | 24 |
def redirect_logout_list(self, request, **kwargs): |
25 | 25 |
from django.urls import reverse |
26 | 26 |
src/authentic2_auth_fc/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2_auth_fc/migrations/0002_auto_20200416_1439.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.29 on 2020-04-16 12:39 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
import django.utils.timezone |
6 | 4 |
from django.db import migrations, models |
src/authentic2_auth_fc/migrations/0003_fcaccount_order1.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.20 on 2019-06-12 21:27 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from collections import Counter |
6 | 4 |
src/authentic2_auth_fc/migrations/0004_fcaccount_order2.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.20 on 2019-06-12 21:27 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations, models |
6 | 4 | |
... | ... | |
18 | 16 |
), |
19 | 17 |
migrations.AlterUniqueTogether( |
20 | 18 |
name='fcaccount', |
21 |
unique_together=set([('sub', 'order'), ('user', 'order')]),
|
|
19 |
unique_together={('sub', 'order'), ('user', 'order')},
|
|
22 | 20 |
), |
23 | 21 |
] |
src/authentic2_auth_fc/utils.py | ||
---|---|---|
132 | 132 |
try: |
133 | 133 |
value = mapping_to_value(mapping, user_info) |
134 | 134 |
except (ValueError, KeyError, NotImplementedError) as e: |
135 |
logger.warning(u'auth_fc: cannot apply mapping %s <- %r: %s', attribute, mapping, e)
|
|
135 |
logger.warning('auth_fc: cannot apply mapping %s <- %r: %s', attribute, mapping, e) |
|
136 | 136 |
continue |
137 | 137 |
if mapping.get('if-tag') and mapping['if-tag'] not in tags: |
138 | 138 |
continue |
... | ... | |
155 | 155 |
continue |
156 | 156 |
setattr(user, attribute, value) |
157 | 157 |
else: |
158 |
logger.warning(u'auth_fc: unknown attribute in user_info mapping: %s', attribute)
|
|
158 |
logger.warning('auth_fc: unknown attribute in user_info mapping: %s', attribute) |
|
159 | 159 |
continue |
160 | 160 |
if mapping.get('tag'): |
161 | 161 |
tags.add(mapping['tag']) |
src/authentic2_auth_fc/views.py | ||
---|---|---|
227 | 227 |
'nonce': nonce, |
228 | 228 |
'acr_values': 'eidas1', |
229 | 229 |
} |
230 |
url = '{0}?{1}'.format(app_settings.authorize_url, urlencode(params))
|
|
230 |
url = f'{app_settings.authorize_url}?{urlencode(params)}'
|
|
231 | 231 |
logger.debug('auth_fc: authorization_request redirect to %s', url) |
232 | 232 | |
233 | 233 |
response = HttpResponseRedirect(url) |
src/authentic2_auth_oidc/admin.py | ||
---|---|---|
29 | 29 | |
30 | 30 |
class OIDCClaimMappingForm(forms.ModelForm): |
31 | 31 |
def __init__(self, *args, **kwargs): |
32 |
super(OIDCClaimMappingForm, self).__init__(*args, **kwargs)
|
|
32 |
super().__init__(*args, **kwargs) |
|
33 | 33 |
claim_widget = self.fields['claim'].widget |
34 | 34 |
# fill datalist with standard claims from |
35 | 35 |
# https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims |
src/authentic2_auth_oidc/app_settings.py | ||
---|---|---|
17 | 17 |
import sys |
18 | 18 | |
19 | 19 | |
20 |
class AppSettings(object):
|
|
20 |
class AppSettings: |
|
21 | 21 |
'''Thanks django-allauth''' |
22 | 22 | |
23 | 23 |
__SENTINEL = object() |
src/authentic2_auth_oidc/apps.py | ||
---|---|---|
18 | 18 |
from django import template |
19 | 19 | |
20 | 20 | |
21 |
class Plugin(object):
|
|
21 |
class Plugin: |
|
22 | 22 |
def revoke_token(self, provider, access_token): |
23 | 23 |
import logging |
24 | 24 |
src/authentic2_auth_oidc/management/commands/oidc-register-issuer.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import print_function |
|
18 | 17 | |
19 | 18 |
import json |
20 | 19 |
import pprint |
src/authentic2_auth_oidc/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
import uuid |
5 | 2 | |
6 | 3 |
import django.contrib.postgres.fields.jsonb |
src/authentic2_auth_oidc/migrations/0002_oidcprovider_token_revocation_endpoint.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_auth_oidc/migrations/0003_oidcprovider_show.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_auth_oidc/migrations/0004_auto_20171017_1522.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_auth_oidc/migrations/0005_oidcprovider_slug.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.12 on 2018-09-28 08:58 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations, models |
6 | 4 |
src/authentic2_auth_oidc/migrations/0006_oidcprovider_claims_parameter_supported.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_auth_oidc/migrations/0007_auto_20200317_1732.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.18 on 2020-03-17 16:32 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations, models |
6 | 4 |
src/authentic2_auth_oidc/models.py | ||
---|---|---|
162 | 162 |
return (self.claim, self.attribute, self.verified, self.required) |
163 | 163 | |
164 | 164 |
def __str__(self): |
165 |
s = '{0} -> {1}'.format(self.claim, self.attribute)
|
|
165 |
s = f'{self.claim} -> {self.attribute}'
|
|
166 | 166 |
if self.verified: |
167 | 167 |
s += ', verified' |
168 | 168 |
if self.required: |
... | ... | |
196 | 196 |
sub = models.CharField(verbose_name=_('sub'), max_length=256) |
197 | 197 | |
198 | 198 |
def __str__(self): |
199 |
return '{0} on {1} linked to {2}'.format(self.sub, self.provider and self.provider.issuer, self.user)
|
|
199 |
return f'{self.sub} on {self.provider and self.provider.issuer} linked to {self.user}'
|
|
200 | 200 | |
201 | 201 |
def __repr__(self): |
202 | 202 |
return '<OIDCAccount %r on %r>' % (self.sub, self.provider and self.provider.issuer) |
src/authentic2_auth_oidc/utils.py | ||
---|---|---|
90 | 90 |
return json_decode(jwt.claims) |
91 | 91 | |
92 | 92 | |
93 |
REQUIRED_ID_TOKEN_KEYS = set(['iss', 'sub', 'aud', 'exp', 'iat'])
|
|
93 |
REQUIRED_ID_TOKEN_KEYS = {'iss', 'sub', 'aud', 'exp', 'iat'}
|
|
94 | 94 |
KEY_TYPES = { |
95 | 95 |
'iss': str, |
96 | 96 |
'sub': str, |
... | ... | |
114 | 114 |
pass |
115 | 115 | |
116 | 116 | |
117 |
class IDToken(object):
|
|
117 |
class IDToken: |
|
118 | 118 |
auth_time = None |
119 | 119 |
nonce = None |
120 | 120 | |
... | ... | |
181 | 181 |
return default |
182 | 182 | |
183 | 183 | |
184 |
OPENID_CONFIGURATION_REQUIRED = set( |
|
185 |
[ |
|
186 |
'issuer', |
|
187 |
'authorization_endpoint', |
|
188 |
'token_endpoint', |
|
189 |
'jwks_uri', |
|
190 |
'response_types_supported', |
|
191 |
'subject_types_supported', |
|
192 |
'id_token_signing_alg_values_supported', |
|
193 |
'userinfo_endpoint', |
|
194 |
] |
|
195 |
) |
|
184 |
OPENID_CONFIGURATION_REQUIRED = { |
|
185 |
'issuer', |
|
186 |
'authorization_endpoint', |
|
187 |
'token_endpoint', |
|
188 |
'jwks_uri', |
|
189 |
'response_types_supported', |
|
190 |
'subject_types_supported', |
|
191 |
'id_token_signing_alg_values_supported', |
|
192 |
'userinfo_endpoint', |
|
193 |
} |
|
196 | 194 | |
197 | 195 | |
198 | 196 |
def check_https(url): |
... | ... | |
256 | 254 |
old_pk = models.OIDCProvider.objects.get(issuer=openid_configuration['issuer']).pk |
257 | 255 |
except models.OIDCProvider.DoesNotExist: |
258 | 256 |
old_pk = None |
259 |
if set(['RS256', 'RS384', 'RS512']) & set(openid_configuration['id_token_signing_alg_values_supported']):
|
|
257 |
if {'RS256', 'RS384', 'RS512'} & set(openid_configuration['id_token_signing_alg_values_supported']):
|
|
260 | 258 |
idtoken_algo = models.OIDCProvider.ALGO_RSA |
261 |
elif set(['HS256', 'HS384', 'HS512']) & set( |
|
262 |
openid_configuration['id_token_signing_alg_values_supported'] |
|
263 |
): |
|
259 |
elif {'HS256', 'HS384', 'HS512'} & set(openid_configuration['id_token_signing_alg_values_supported']): |
|
264 | 260 |
idtoken_algo = models.OIDCProvider.ALGO_HMAC |
265 |
elif set(['ES256', 'ES384', 'ES512']) & set( |
|
266 |
openid_configuration['id_token_signing_alg_values_supported'] |
|
267 |
): |
|
261 |
elif {'ES256', 'ES384', 'ES512'} & set(openid_configuration['id_token_signing_alg_values_supported']): |
|
268 | 262 |
idtoken_algo = models.OIDCProvider.ALGO_EC |
269 | 263 |
else: |
270 | 264 |
raise ValueError( |
src/authentic2_auth_oidc/views.py | ||
---|---|---|
47 | 47 |
@setting_enabled('ENABLE', settings=app_settings) |
48 | 48 |
def oidc_login(request, pk, next_url=None, *args, **kwargs): |
49 | 49 |
provider = get_provider(pk) |
50 |
scopes = set(provider.scopes.split()) | set(['openid'])
|
|
50 |
scopes = set(provider.scopes.split()) | {'openid'}
|
|
51 | 51 |
state_id = str(uuid.uuid4()) |
52 | 52 |
next_url = next_url or request.GET.get(REDIRECT_FIELD_NAME, '') |
53 | 53 |
if next_url and not good_next_url(request, next_url): |
src/authentic2_auth_saml/adapters.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import unicode_literals |
|
18 | 17 | |
19 | 18 |
import logging |
20 | 19 | |
... | ... | |
40 | 39 | |
41 | 40 |
def __init__(self, message, details=None): |
42 | 41 |
self.details = details or {} |
43 |
super(MappingError, self).__init__(message)
|
|
42 |
super().__init__(message) |
|
44 | 43 | |
45 | 44 |
def __str__(self): |
46 | 45 |
s = str(self.args[0]) |
... | ... | |
49 | 48 |
return s |
50 | 49 | |
51 | 50 | |
52 |
class SamlConditionContextProxy(object):
|
|
51 |
class SamlConditionContextProxy: |
|
53 | 52 |
def __init__(self, saml_attributes): |
54 | 53 |
self.saml_attributes = saml_attributes |
55 | 54 | |
... | ... | |
84 | 83 |
user.save() |
85 | 84 | |
86 | 85 |
def provision(self, user, idp, saml_attributes): |
87 |
super(AuthenticAdapter, self).provision(user, idp, saml_attributes)
|
|
86 |
super().provision(user, idp, saml_attributes) |
|
88 | 87 |
try: |
89 | 88 |
self.provision_a2_attributes(user, idp, saml_attributes) |
90 | 89 |
except MappingError as e: |
src/authentic2_auth_saml/app_settings.py | ||
---|---|---|
17 | 17 |
import sys |
18 | 18 | |
19 | 19 | |
20 |
class AppSettings(object):
|
|
20 |
class AppSettings: |
|
21 | 21 |
'''Thanks django-allauth''' |
22 | 22 | |
23 | 23 |
__SENTINEL = object() |
src/authentic2_auth_saml/backends.py | ||
---|---|---|
25 | 25 |
def authenticate(self, request=None, **kwargs): |
26 | 26 |
if not app_settings.enable: |
27 | 27 |
return None |
28 |
return super(SAMLBackend, self).authenticate(request=request, **kwargs)
|
|
28 |
return super().authenticate(request=request, **kwargs) |
|
29 | 29 | |
30 | 30 |
def get_saml2_authn_context(self): |
31 | 31 |
# Pass AuthnContextClassRef from the previous IdP |
src/authentic2_idp_cas/admin.py | ||
---|---|---|
29 | 29 | |
30 | 30 |
class ServiceForm(forms.ModelForm): |
31 | 31 |
def __init__(self, *args, **kwargs): |
32 |
super(ServiceForm, self).__init__(*args, **kwargs)
|
|
32 |
super().__init__(*args, **kwargs) |
|
33 | 33 |
choices = self.choices({'user': None, 'request': None, 'service': self.instance}) |
34 | 34 |
self.fields['identifier_attribute'].choices = choices |
35 | 35 |
self.fields['identifier_attribute'].widget = forms.Select(choices=choices) |
... | ... | |
46 | 46 |
class AttributeInlineForm(forms.ModelForm): |
47 | 47 |
def __init__(self, *args, **kwargs): |
48 | 48 |
service = kwargs.pop('service', None) |
49 |
super(AttributeInlineForm, self).__init__(*args, **kwargs)
|
|
49 |
super().__init__(*args, **kwargs) |
|
50 | 50 |
choices = self.choices({'user': None, 'request': None, 'service': service}) |
51 | 51 |
self.fields['attribute_name'].choices = choices |
52 | 52 |
self.fields['attribute_name'].widget = forms.Select(choices=choices) |
... | ... | |
73 | 73 |
class NewForm(self.form): |
74 | 74 |
def __init__(self, *args, **kwargs): |
75 | 75 |
kwargs['service'] = obj |
76 |
super(NewForm, self).__init__(*args, **kwargs)
|
|
76 |
super().__init__(*args, **kwargs) |
|
77 | 77 | |
78 | 78 |
kwargs['form'] = NewForm |
79 |
return super(AttributeInlineAdmin, self).get_formset(request, obj=obj, **kwargs)
|
|
79 |
return super().get_formset(request, obj=obj, **kwargs) |
|
80 | 80 | |
81 | 81 | |
82 | 82 |
class ServiceAdmin(admin.ModelAdmin): |
src/authentic2_idp_cas/app_settings.py | ||
---|---|---|
17 | 17 |
import sys |
18 | 18 | |
19 | 19 | |
20 |
class AppSettings(object):
|
|
20 |
class AppSettings: |
|
21 | 21 |
__DEFAULTS = { |
22 | 22 |
'ENABLE': False, |
23 | 23 |
# allow do tisable check of pgt url for testing purpose |
src/authentic2_idp_cas/apps.py | ||
---|---|---|
20 | 20 |
from .constants import SESSION_CAS_LOGOUTS |
21 | 21 | |
22 | 22 | |
23 |
class Plugin(object):
|
|
23 |
class Plugin: |
|
24 | 24 |
def logout_list(self, request): |
25 | 25 |
fragments = [] |
26 | 26 |
cas_logouts = request.session.get(SESSION_CAS_LOGOUTS, []) |
src/authentic2_idp_cas/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
import authentic2_idp_cas.models |
... | ... | |
147 | 144 |
), |
148 | 145 |
migrations.AlterUniqueTogether( |
149 | 146 |
name='attribute', |
150 |
unique_together=set([('service', 'slug', 'attribute_name')]),
|
|
147 |
unique_together={('service', 'slug', 'attribute_name')},
|
|
151 | 148 |
), |
152 | 149 |
] |
src/authentic2_idp_cas/migrations/0002_auto_20150410_1438.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2_idp_cas/migrations/0003_auto_20150415_2223.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_cas/migrations/0004_create_services.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_cas/migrations/0005_alter_field_service_ptr.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_cas/migrations/0006_copy_proxy_m2m.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_cas/migrations/0007_alter_service.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_cas/migrations/0008_alter_foreign_keys.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_cas/migrations/0009_alter_related_models.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_cas/migrations/0010_copy_service_ptr_id_to_old_id.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_cas/migrations/0011_remove_old_id_restore_proxy.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_cas/migrations/0012_copy_service_proxy_to_m2m.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_cas/migrations/0013_delete_model_service_proxy2.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_cas/migrations/0014_auto_20151204_1606.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_cas/migrations/0015_auto_20170406_1825.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_cas/models.py | ||
---|---|---|
44 | 44 | |
45 | 45 |
def clean(self): |
46 | 46 |
'''Check urls is a space separated list of urls and normalize it''' |
47 |
super(Service, self).clean()
|
|
47 |
super().clean() |
|
48 | 48 |
urls = self.urls.split(' ') |
49 | 49 |
for url in urls: |
50 | 50 |
try: |
... | ... | |
66 | 66 | |
67 | 67 |
def get_wanted_attributes(self): |
68 | 68 |
'''Compute wanted attributes for this service''' |
69 |
wanted = set([self.identifier_attribute])
|
|
69 |
wanted = {self.identifier_attribute}
|
|
70 | 70 |
for attribute in self.attribute_set.all(): |
71 | 71 |
wanted.add(attribute.attribute_name) |
72 | 72 |
return list(wanted) |
src/authentic2_idp_cas/views.py | ||
---|---|---|
87 | 87 |
ET._namespace_map['http://www.yale.edu/tp/cas'] = 'cas' |
88 | 88 | |
89 | 89 | |
90 |
class CasMixin(object):
|
|
90 |
class CasMixin: |
|
91 | 91 |
'''Common methods''' |
92 | 92 | |
93 | 93 |
def __init__(self, *args, **kwargs): |
src/authentic2_idp_oidc/admin.py | ||
---|---|---|
26 | 26 | |
27 | 27 |
class OIDCClaimInlineForm(forms.ModelForm): |
28 | 28 |
def __init__(self, *args, **kwargs): |
29 |
super(OIDCClaimInlineForm, self).__init__(*args, **kwargs)
|
|
29 |
super().__init__(*args, **kwargs) |
|
30 | 30 |
data = dict(get_service_attributes(getattr(self.instance, 'client', None))).keys() |
31 | 31 |
widget = self.fields['value'].widget |
32 | 32 |
widget.data = data |
... | ... | |
54 | 54 |
if request.method == 'GET' and not obj: |
55 | 55 |
initial.extend(app_settings.DEFAULT_MAPPINGS) |
56 | 56 |
self.extra = 5 |
57 |
formset = super(OIDCClaimInlineAdmin, self).get_formset(request, obj=obj, **kwargs)
|
|
57 |
formset = super().get_formset(request, obj=obj, **kwargs) |
|
58 | 58 |
formset.__init__ = curry(formset.__init__, initial=initial) |
59 | 59 |
return formset |
60 | 60 | |
... | ... | |
74 | 74 |
readonly_fields = ['created', 'expired'] |
75 | 75 | |
76 | 76 |
def get_queryset(self, request): |
77 |
qs = super(OIDCAuthorizationAdmin, self).get_queryset(request)
|
|
77 |
qs = super().get_queryset(request) |
|
78 | 78 |
qs = qs.prefetch_related('client') |
79 | 79 |
return qs |
80 | 80 | |
... | ... | |
83 | 83 | |
84 | 84 |
from authentic2.a2_rbac.models import OrganizationalUnit as OU |
85 | 85 | |
86 |
queryset, use_distinct = super(OIDCAuthorizationAdmin, self).get_search_results( |
|
87 |
request, queryset, search_term |
|
88 |
) |
|
86 |
queryset, use_distinct = super().get_search_results(request, queryset, search_term) |
|
89 | 87 |
clients = models.OIDCClient.objects.filter(name__contains=search_term).values_list('pk') |
90 | 88 |
ous = OU.objects.filter(name__contains=search_term).values_list('pk') |
91 | 89 |
queryset |= self.model.objects.filter( |
src/authentic2_idp_oidc/app_settings.py | ||
---|---|---|
17 | 17 |
import sys |
18 | 18 | |
19 | 19 | |
20 |
class AppSettings(object):
|
|
20 |
class AppSettings: |
|
21 | 21 |
'''Thanks django-allauth''' |
22 | 22 | |
23 | 23 |
__SENTINEL = object() |
src/authentic2_idp_oidc/apps.py | ||
---|---|---|
19 | 19 |
from django.utils.encoding import smart_bytes |
20 | 20 | |
21 | 21 | |
22 |
class Plugin(object):
|
|
22 |
class Plugin: |
|
23 | 23 |
def logout_list(self, request): |
24 | 24 |
from . import app_settings |
25 | 25 |
from .utils import get_oidc_sessions |
src/authentic2_idp_oidc/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/authentic2_idp_oidc/migrations/0002_auto_20170121_2346.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
import authentic2_idp_oidc.models |
src/authentic2_idp_oidc/migrations/0003_auto_20170329_1259.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
import authentic2_idp_oidc.models |
src/authentic2_idp_oidc/migrations/0004_auto_20170324_1426.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_oidc/migrations/0005_authorization_mode.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_oidc/migrations/0006_auto_20170720_1054.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_oidc/migrations/0007_oidcclient_has_api_access.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_oidc/migrations/0008_oidcclient_idtoken_duration.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_oidc/migrations/0009_auto_20180313_1156.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_oidc/migrations/0010_oidcclaim.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/authentic2_idp_oidc/migrations/0011_auto_20180808_1546.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations |
5 | 2 | |
6 | 3 |
OLD_DEFAULT_CLAIMS_MAPPING = { |
src/authentic2_idp_oidc/migrations/0012_auto_20200122_2258.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# Generated by Django 1.11.20 on 2020-01-22 21:58 |
3 |
from __future__ import unicode_literals |
|
4 | 2 | |
5 | 3 |
from django.db import migrations, models |
6 | 4 |
src/authentic2_idp_oidc/models.py | ||
---|---|---|
271 | 271 |
return None |
272 | 272 | |
273 | 273 | |
274 |
class SessionMixin(object):
|
|
274 |
class SessionMixin: |
|
275 | 275 |
@property |
276 | 276 |
def session(self): |
277 | 277 |
if not hasattr(self, '_session'): |
src/authentic2_idp_oidc/utils.py | ||
---|---|---|
105 | 105 | |
106 | 106 |
def scope_set(data): |
107 | 107 |
'''Convert a scope string into a set of scopes''' |
108 |
return set([scope.strip() for scope in data.split()])
|
|
108 |
return {scope.strip() for scope in data.split()}
|
|
109 | 109 | |
110 | 110 | |
111 | 111 |
def clean_words(data): |
src/authentic2_idp_oidc/views.py | ||
---|---|---|
289 | 289 |
if response_type != 'code': |
290 | 290 |
raise UnsupportedResponseType(_('Response type must be "code"')) |
291 | 291 |
elif client.authorization_flow == client.FLOW_IMPLICIT: |
292 |
if not set(filter(None, response_type.split())) in (set(['id_token', 'token']), set(['id_token'])):
|
|
292 |
if not set(filter(None, response_type.split())) in ({'id_token', 'token'}, {'id_token'}):
|
|
293 | 293 |
raise UnsupportedResponseType(_('Response type must be "id_token token" or "id_token"')) |
294 | 294 |
else: |
295 | 295 |
raise NotImplementedError |
... | ... | |
403 | 403 |
'authentic2_idp_oidc/authorization.html', |
404 | 404 |
{ |
405 | 405 |
'client': client, |
406 |
'scopes': scopes - set(['openid']),
|
|
406 |
'scopes': scopes - {'openid'},
|
|
407 | 407 |
}, |
408 | 408 |
) |
409 | 409 |
if response_type == 'code': |
src/django_rbac/backends.py | ||
---|---|---|
25 | 25 |
return field.related_model |
26 | 26 | |
27 | 27 | |
28 |
class DjangoRBACBackend(object):
|
|
28 |
class DjangoRBACBackend: |
|
29 | 29 |
_DEFAULT_DJANGO_RBAC_PERMISSIONS_HIERARCHY = { |
30 | 30 |
'view': ['search'], |
31 | 31 |
'admin': ['change', 'delete', 'add', 'view', 'search'], |
... | ... | |
99 | 99 |
key = '%s.%s' % (ct.id, obj.pk) |
100 | 100 |
if key in perms_cache: |
101 | 101 |
permissions.update(perms_cache[key]) |
102 |
for permission in perms_cache.get('__all__', set([])):
|
|
102 |
for permission in perms_cache.get('__all__', set()): |
|
103 | 103 |
if permission.startswith('%s.' % ct.app_label) and permission.endswith('_%s' % ct.model): |
104 | 104 |
permissions.add(permission) |
105 | 105 |
if hasattr(obj, 'ou_id') and obj.ou_id: |
src/django_rbac/context_processors.py | ||
---|---|---|
4 | 4 |
from django.contrib.auth.context_processors import PermWrapper as AuthPermWrapper |
5 | 5 | |
6 | 6 | |
7 |
class PermAnyLookupDict(object):
|
|
7 |
class PermAnyLookupDict: |
|
8 | 8 |
def __init__(self, user, app_label): |
9 | 9 |
self.user = user |
10 | 10 |
self.app_label = app_label |
... | ... | |
20 | 20 |
raise TypeError('PermAnyLookupDict has not boolean value') |
21 | 21 | |
22 | 22 | |
23 |
class PermAnyWrapper(object):
|
|
23 |
class PermAnyWrapper: |
|
24 | 24 |
def __init__(self, user): |
25 | 25 |
self.user = user |
26 | 26 | |
... | ... | |
42 | 42 |
def __getitem__(self, app_label): |
43 | 43 |
if app_label == 'any': |
44 | 44 |
return PermAnyWrapper(self.user) |
45 |
return super(PermWrapper, self).__getitem__(app_label)
|
|
45 |
return super().__getitem__(app_label) |
|
46 | 46 | |
47 | 47 | |
48 | 48 |
def auth(request): |
src/django_rbac/management/commands/cleanup_rbac.py | ||
---|---|---|
1 |
from __future__ import print_function |
|
2 | ||
3 | 1 |
from django.core.management.base import BaseCommand |
4 | 2 | |
5 | 3 |
src/django_rbac/migrations/0001_initial.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/django_rbac/migrations/0002_organizationalunit_permission_role_roleparenting.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/django_rbac/migrations/0003_add_max_aggregate_for_postgres.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations |
5 | 2 | |
6 | 3 |
src/django_rbac/migrations/0004_auto_20150708_1337.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.conf import settings |
5 | 2 |
from django.db import migrations, models |
6 | 3 |
src/django_rbac/migrations/0005_auto_20171209_1106.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 | ||
4 | 1 |
from django.db import migrations, models |
5 | 2 | |
6 | 3 |
src/django_rbac/models.py | ||
---|---|---|
39 | 39 |
return self.name |
40 | 40 | |
41 | 41 |
def __repr__(self): |
42 |
return '<{0} {1} {2}>'.format(self.__class__.__name__, repr(self.slug), repr(self.name))
|
|
42 |
return f'<{self.__class__.__name__} {repr(self.slug)} {repr(self.name)}>'
|
|
43 | 43 | |
44 | 44 |
def save(self, *args, **kwargs): |
45 | 45 |
# truncate slug and add a hash if it's too long |
... | ... | |
49 | 49 |
self.slug = self.slug[:252] + hashlib.md5(self.slug).hexdigest()[:4] |
50 | 50 |
if not self.uuid: |
51 | 51 |
self.uuid = utils.get_hex_uuid() |
52 |
return super(AbstractBase, self).save(*args, **kwargs)
|
|
52 |
return super().save(*args, **kwargs) |
|
53 | 53 | |
54 | 54 |
def natural_key(self): |
55 | 55 |
return [self.uuid] |
... | ... | |
159 | 159 |
ct_ct = ContentType.objects.get_for_model(ContentType) |
160 | 160 |
if ct == ct_ct: |
161 | 161 |
target = ContentType.objects.get_for_id(self.target_id) |
162 |
s = '{0} / {1}'.format(self.operation, target)
|
|
162 |
s = f'{self.operation} / {target}'
|
|
163 | 163 |
else: |
164 |
s = '{0} / {1} / {2}'.format(self.operation, ct, self.target)
|
|
164 |
s = f'{self.operation} / {ct} / {self.target}'
|
|
165 | 165 |
if self.ou: |
166 |
s += _(u' (scope "{0}")').format(self.ou)
|
|
166 |
s += _(' (scope "{0}")').format(self.ou) |
|
167 | 167 |
return s |
168 | 168 | |
169 | 169 |
class Meta: |
tests/auth_fc/test_auth_fc.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - authentic2 authentication for FranceConnect |
3 | 2 |
# Copyright (C) 2020 Entr'ouvert |
4 | 3 |
# |
... | ... | |
19 | 18 |
import json |
20 | 19 |
import re |
21 | 20 |
import urllib.parse |
21 |
from unittest import mock |
|
22 | 22 | |
23 |
import mock |
|
24 | 23 |
import pytest |
25 | 24 |
import requests |
26 | 25 |
from django.contrib.auth import get_user_model |
tests/auth_fc/test_auth_fc_api.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2-auth-fc - authentic2 authentication for FranceConnect |
3 | 2 |
# Copyright (C) 2019 Entr'ouvert |
4 | 3 |
# |
tests/conftest.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
... | ... | |
17 | 16 | |
18 | 17 | |
19 | 18 |
import urllib.parse |
19 |
from unittest import mock |
|
20 | 20 | |
21 | 21 |
import django |
22 | 22 |
import django_webtest |
23 |
import mock |
|
24 | 23 |
import pytest |
25 | 24 |
from django.contrib.auth import get_user_model |
26 | 25 |
from django.core.cache import cache |
... | ... | |
130 | 129 |
@pytest.fixture |
131 | 130 |
def simple_user(db, ou1): |
132 | 131 |
return create_user( |
133 |
username='user', first_name=u'Jôhn', last_name=u'Dôe', email='user@example.net', ou=get_default_ou()
|
|
132 |
username='user', first_name='Jôhn', last_name='Dôe', email='user@example.net', ou=get_default_ou()
|
|
134 | 133 |
) |
135 | 134 | |
136 | 135 | |
... | ... | |
165 | 164 |
@pytest.fixture |
166 | 165 |
def user_ou1(db, ou1): |
167 | 166 |
return create_user( |
168 |
username='john.doe', first_name=u'Jôhn', last_name=u'Dôe', email='john.doe@example.net', ou=ou1
|
|
167 |
username='john.doe', first_name='Jôhn', last_name='Dôe', email='john.doe@example.net', ou=ou1
|
|
169 | 168 |
) |
170 | 169 | |
171 | 170 | |
172 | 171 |
@pytest.fixture |
173 | 172 |
def user_ou2(db, ou2): |
174 | 173 |
return create_user( |
175 |
username='john.doe.ou2', first_name=u'Jôhn', last_name=u'Dôe', email='john.doe@example.net', ou=ou2
|
|
174 |
username='john.doe.ou2', first_name='Jôhn', last_name='Dôe', email='john.doe@example.net', ou=ou2
|
|
176 | 175 |
) |
177 | 176 | |
178 | 177 | |
179 | 178 |
@pytest.fixture |
180 | 179 |
def admin_ou1(db, ou1): |
181 | 180 |
user = create_user( |
182 |
username='admin.ou1', first_name=u'Admin', last_name=u'OU1', email='admin.ou1@example.net', ou=ou1
|
|
181 |
username='admin.ou1', first_name='Admin', last_name='OU1', email='admin.ou1@example.net', ou=ou1
|
|
183 | 182 |
) |
184 | 183 |
user.roles.add(ou1.get_admin_role()) |
185 | 184 |
return user |
... | ... | |
188 | 187 |
@pytest.fixture |
189 | 188 |
def admin_ou2(db, ou2): |
190 | 189 |
user = create_user( |
191 |
username='admin.ou2', first_name=u'Admin', last_name=u'OU2', email='admin.ou2@example.net', ou=ou2
|
|
190 |
username='admin.ou2', first_name='Admin', last_name='OU2', email='admin.ou2@example.net', ou=ou2
|
|
192 | 191 |
) |
193 | 192 |
user.roles.add(ou2.get_admin_role()) |
194 | 193 |
return user |
... | ... | |
297 | 296 | |
298 | 297 |
class TestOIDCUser(OIDCUser): |
299 | 298 |
def __init__(self, oidc_client): |
300 |
super(TestOIDCUser, self).__init__(oidc_client)
|
|
299 |
super().__init__(oidc_client) |
|
301 | 300 | |
302 | 301 |
@property |
303 | 302 |
def username(self): |
... | ... | |
353 | 352 |
cached_el.cache.clear() |
354 | 353 | |
355 | 354 | |
356 |
class AllHook(object):
|
|
355 |
class AllHook: |
|
357 | 356 |
def __init__(self): |
358 | 357 |
self.calls = {} |
359 | 358 | |
... | ... | |
391 | 390 |
def user_with_auto_admin_role(auto_admin_role, ou1): |
392 | 391 |
user = create_user( |
393 | 392 |
username='user.with.auto.admin.role', |
394 |
first_name=u'User',
|
|
395 |
last_name=u'With Auto Admin Role',
|
|
393 |
first_name='User', |
|
394 |
last_name='With Auto Admin Role', |
|
396 | 395 |
email='user.with.auto.admin.role@example.net', |
397 | 396 |
ou=ou1, |
398 | 397 |
) |
... | ... | |
502 | 501 |
Based on: https://gist.github.com/blueyed/4fb0a807104551f103e6 |
503 | 502 |
""" |
504 | 503 | |
505 |
class Migrator(object):
|
|
504 |
class Migrator: |
|
506 | 505 |
def before(self, targets, at_end=True): |
507 | 506 |
"""Specify app and starting migration names as in: |
508 | 507 |
before([('app', '0001_before')]) => app/migrations/0001_before.py |
tests/idp_oidc/test_api.py | ||
---|---|---|
25 | 25 |
users = [User.objects.create(username='user-%s' % i) for i in range(10)] |
26 | 26 |
for user in users[5:]: |
27 | 27 |
user.delete() |
28 |
deleted_subs = set(make_sub(oidc_client, user) for user in users[5:])
|
|
28 |
deleted_subs = {make_sub(oidc_client, user) for user in users[5:]}
|
|
29 | 29 | |
30 | 30 |
app.authorization = ('Basic', (oidc_client.client_id, oidc_client.client_secret)) |
31 | 31 |
status = 200 |
tests/idp_oidc/test_misc.py | ||
---|---|---|
150 | 150 |
utils.login(app, simple_user) |
151 | 151 |
response = app.get(authorize_url) |
152 | 152 |
if not login_first: |
153 |
assert set(app.session['login-hint']) == set(['backoffice', 'john@example.com'])
|
|
153 |
assert set(app.session['login-hint']) == {'backoffice', 'john@example.com'}
|
|
154 | 154 |
response = response.follow() |
155 | 155 |
assert response.request.path == reverse('auth_login') |
156 | 156 |
response.form.set('username', simple_user.username) |
... | ... | |
205 | 205 |
location = urllib.parse.urlparse(response['Location']) |
206 | 206 |
if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE: |
207 | 207 |
query = urllib.parse.parse_qs(location.query) |
208 |
assert set(query.keys()) == set(['code', 'state'])
|
|
208 |
assert set(query.keys()) == {'code', 'state'}
|
|
209 | 209 |
assert query['code'] == [code.uuid] |
210 | 210 |
code = query['code'][0] |
211 | 211 |
assert query['state'] == ['xxx'] |
... | ... | |
232 | 232 |
query = urllib.parse.parse_qs(location.fragment) |
233 | 233 |
assert OIDCAccessToken.objects.count() == 1 |
234 | 234 |
access_token = OIDCAccessToken.objects.get() |
235 |
assert set(query.keys()) == set(['access_token', 'token_type', 'expires_in', 'id_token', 'state'])
|
|
235 |
assert set(query.keys()) == {'access_token', 'token_type', 'expires_in', 'id_token', 'state'}
|
|
236 | 236 |
assert query['access_token'] == [access_token.uuid] |
237 | 237 |
assert query['token_type'] == ['Bearer'] |
238 | 238 |
assert query['state'] == ['xxx'] |
... | ... | |
250 | 250 |
raise NotImplementedError |
251 | 251 |
jwt = JWT(jwt=id_token, key=key, algs=algs) |
252 | 252 |
claims = json.loads(jwt.claims) |
253 |
assert set(claims) >= set(['iss', 'sub', 'aud', 'exp', 'iat', 'nonce', 'auth_time', 'acr'])
|
|
253 |
assert set(claims) >= {'iss', 'sub', 'aud', 'exp', 'iat', 'nonce', 'auth_time', 'acr'}
|
|
254 | 254 |
assert claims['nonce'] == 'yyy' |
255 | 255 |
assert response.request.url.startswith(claims['iss']) |
256 | 256 |
assert claims['aud'] == oidc_client.client_id |
... | ... | |
776 | 776 |
code.save() |
777 | 777 |
location = urllib.parse.urlparse(response['Location']) |
778 | 778 |
query = urllib.parse.parse_qs(location.query) |
779 |
assert set(query.keys()) == set(['code'])
|
|
779 |
assert set(query.keys()) == {'code'}
|
|
780 | 780 |
assert query['code'] == [code.uuid] |
781 | 781 |
code = query['code'][0] |
782 | 782 |
token_url = make_url('oidc-token') |
... | ... | |
1288 | 1288 |
# jwt deserialization implicitly checks the token signature: |
1289 | 1289 |
jwt.deserialize(token, key=jwk) |
1290 | 1290 |
claims = json.loads(jwt.claims) |
1291 |
assert set(claims) == set(['acr', 'aud', 'auth_time', 'exp', 'iat', 'iss', 'sub'])
|
|
1291 |
assert set(claims) == {'acr', 'aud', 'auth_time', 'exp', 'iat', 'iss', 'sub'}
|
|
1292 | 1292 |
assert all(claims.values()) |
1293 | 1293 | |
1294 | 1294 |
# 2. test basic authz |
... | ... | |
1303 | 1303 |
# jwt deserialization implicitly checks the token signature: |
1304 | 1304 |
jwt.deserialize(token, key=jwk) |
1305 | 1305 |
claims = json.loads(jwt.claims) |
1306 |
assert set(claims) == set(['acr', 'aud', 'auth_time', 'exp', 'iat', 'iss', 'sub'])
|
|
1306 |
assert set(claims) == {'acr', 'aud', 'auth_time', 'exp', 'iat', 'iss', 'sub'}
|
|
1307 | 1307 |
assert all(claims.values()) |
1308 | 1308 | |
1309 | 1309 |
tests/test_a2_rbac.py | ||
---|---|---|
113 | 113 | |
114 | 114 | |
115 | 115 |
def test_role_clean(db): |
116 |
coin = Role(name=u'Coin')
|
|
116 |
coin = Role(name='Coin') |
|
117 | 117 |
coin.clean() |
118 | 118 |
coin.save() |
119 | 119 |
assert coin.slug == 'coin' |
... | ... | |
190 | 190 |
attributes = role_dict['attributes'] |
191 | 191 |
assert len(attributes) == 2 |
192 | 192 | |
193 |
expected_attr_names = set([attr1.name, attr2.name])
|
|
193 |
expected_attr_names = {attr1.name, attr2.name}
|
|
194 | 194 |
for attr_dict in attributes: |
195 | 195 |
assert attr_dict['name'] in expected_attr_names |
196 | 196 |
expected_attr_names.remove(attr_dict['name']) |
... | ... | |
213 | 213 |
assert child_role_dict['slug'] == child_role.slug |
214 | 214 |
parents = child_role_dict['parents'] |
215 | 215 |
assert len(parents) == 2 |
216 |
expected_slugs = set([parent_1_role.slug, parent_2_role.slug])
|
|
216 |
expected_slugs = {parent_1_role.slug, parent_2_role.slug}
|
|
217 | 217 |
for parent in parents: |
218 | 218 |
assert parent['slug'] in expected_slugs |
219 | 219 |
expected_slugs.remove(parent['slug']) |
... | ... | |
404 | 404 |
response = response.click('role_ou1') |
405 | 405 |
select2_json = request_select2(app, response) |
406 | 406 |
assert select2_json['more'] is False |
407 |
assert set(result['id'] for result in select2_json['results']) == set( |
|
408 |
[simple_user.id, user_ou1.id, admin.id] |
|
409 |
) |
|
407 |
assert {result['id'] for result in select2_json['results']} == {simple_user.id, user_ou1.id, admin.id} |
|
410 | 408 | |
411 | 409 |
# with A2_RBAC_ROLE_ADMIN_RESTRICT_TO_OU_USERS after a reload of the admin |
412 | 410 |
# page, we should only see user from the same OU as the role |
... | ... | |
416 | 414 |
response = response.click('role_ou1') |
417 | 415 |
select2_json = request_select2(app, response) |
418 | 416 |
assert select2_json['more'] is False |
419 |
assert set(result['id'] for result in select2_json['results']) == set([user_ou1.id])
|
|
417 |
assert {result['id'] for result in select2_json['results']} == {user_ou1.id}
|
|
420 | 418 | |
421 | 419 | |
422 | 420 |
def test_no_managed_ct(transactional_db, settings): |
... | ... | |
464 | 462 |
assert manager.parents(include_self=False).count() == 4 |
465 | 463 | |
466 | 464 |
for ou in [get_default_ou(), ou1]: |
467 |
manager = Role.objects.get(ou__isnull=True, slug='_a2-managers-of-{ou.slug}'.format(ou=ou))
|
|
468 |
user_manager = Role.objects.get(ou=ou, slug='_a2-manager-of-users-{ou.slug}'.format(ou=ou))
|
|
469 |
role_manager = Role.objects.get(ou=ou, slug='_a2-manager-of-roles-{ou.slug}'.format(ou=ou))
|
|
470 |
service_manager = Role.objects.get(ou=ou, slug='_a2-manager-of-services-{ou.slug}'.format(ou=ou))
|
|
465 |
manager = Role.objects.get(ou__isnull=True, slug=f'_a2-managers-of-{ou.slug}')
|
|
466 |
user_manager = Role.objects.get(ou=ou, slug=f'_a2-manager-of-users-{ou.slug}')
|
|
467 |
role_manager = Role.objects.get(ou=ou, slug=f'_a2-manager-of-roles-{ou.slug}')
|
|
468 |
service_manager = Role.objects.get(ou=ou, slug=f'_a2-manager-of-services-{ou.slug}')
|
|
471 | 469 | |
472 | 470 |
assert user_manager in manager.parents() |
473 | 471 |
assert role_manager in manager.parents() |
tests/test_admin.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
... | ... | |
15 | 14 |
# You should have received a copy of the GNU Affero General Public License |
16 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 16 | |
18 |
from __future__ import unicode_literals |
|
19 | 17 | |
20 | 18 |
from urllib.parse import urlparse |
21 | 19 | |
... | ... | |
52 | 50 |
superuser.verified_attributes.last_name = 'Doe' |
53 | 51 | |
54 | 52 |
resp = app.get('/admin/custom_user/user/%s/' % superuser.pk).maybe_follow() |
55 |
assert set(resp.form.fields.keys()) >= set( |
|
56 |
[ |
|
57 |
'username', |
|
58 |
'first_name', |
|
59 |
'last_name', |
|
60 |
'civilite', |
|
61 |
'siret', |
|
62 |
'is_staff', |
|
63 |
'is_superuser', |
|
64 |
'ou', |
|
65 |
'groups', |
|
66 |
'date_joined_0', |
|
67 |
'date_joined_1', |
|
68 |
'last_login_0', |
|
69 |
'last_login_1', |
|
70 |
] |
|
71 |
) |
|
53 |
assert set(resp.form.fields.keys()) >= { |
|
54 |
'username', |
|
55 |
'first_name', |
|
56 |
'last_name', |
|
57 |
'civilite', |
|
58 |
'siret', |
|
59 |
'is_staff', |
|
60 |
'is_superuser', |
|
61 |
'ou', |
|
62 |
'groups', |
|
63 |
'date_joined_0', |
|
64 |
'date_joined_1', |
|
65 |
'last_login_0', |
|
66 |
'last_login_1', |
|
67 |
} |
|
72 | 68 |
resp.form.set('first_name', 'John') |
73 | 69 |
resp.form.set('last_name', 'Doe') |
74 | 70 |
resp.form.set('civilite', 'Mr') |
tests/test_all.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
... | ... | |
223 | 222 |
models.Attribute.objects.update(disabled=True) |
224 | 223 | |
225 | 224 |
models.Attribute.objects.create( |
226 |
label=u'custom',
|
|
225 |
label='custom', |
|
227 | 226 |
name='custom', |
228 | 227 |
required=True, |
229 | 228 |
user_visible=True, |
... | ... | |
231 | 230 |
kind='string', |
232 | 231 |
) |
233 | 232 |
models.Attribute.objects.create( |
234 |
label=u'ID', name='national_number', user_editable=True, user_visible=True, kind='string'
|
|
233 |
label='ID', name='national_number', user_editable=True, user_visible=True, kind='string' |
|
235 | 234 |
) |
236 | 235 |
self.assertTrue(self.client.login(request=None, username='testbot', password='secret')) |
237 | 236 | |
... | ... | |
241 | 240 | |
242 | 241 |
kwargs = {'custom': 'random data', 'national_number': 'xx20153566342yy'} |
243 | 242 |
if form.prefix: |
244 |
kwargs = dict(('%s-%s' % (form.prefix, k), v) for k, v in kwargs.items())
|
|
243 |
kwargs = {'%s-%s' % (form.prefix, k): v for k, v in kwargs.items()}
|
|
245 | 244 | |
246 | 245 |
response = self.client.post(reverse('profile_edit'), kwargs) |
247 | 246 |
new = {'custom': 'random data', 'next_url': '', 'national_number': 'xx20153566342yy'} |
... | ... | |
265 | 264 |
models.Attribute.objects.update(disabled=True) |
266 | 265 | |
267 | 266 |
models.Attribute.objects.create( |
268 |
label=u'custom', name='custom', required=False, user_editable=False, kind='string'
|
|
267 |
label='custom', name='custom', required=False, user_editable=False, kind='string' |
|
269 | 268 |
) |
270 | 269 |
models.Attribute.objects.create( |
271 |
label=u'ID', name='national_number', user_editable=False, user_visible=False, kind='string'
|
|
270 |
label='ID', name='national_number', user_editable=False, user_visible=False, kind='string' |
|
272 | 271 |
) |
273 | 272 | |
274 | 273 |
self.assertTrue(self.client.login(request=None, username='testbot', password='secret')) |
275 | 274 |
response = self.client.get(reverse('profile_edit')) |
276 | 275 |
form = get_response_form(response) |
277 |
self.assertEqual(set(form.fields), set(['next_url']))
|
|
276 |
self.assertEqual(set(form.fields), {'next_url'})
|
|
278 | 277 | |
279 | 278 | |
280 | 279 |
class CacheTests(TestCase): |
... | ... | |
291 | 290 |
class GlobalCache(CacheDecoratorBase): |
292 | 291 |
def __init__(self, *args, **kwargs): |
293 | 292 |
self.cache = {} |
294 |
super(GlobalCache, self).__init__(*args, **kwargs)
|
|
293 |
super().__init__(*args, **kwargs) |
|
295 | 294 | |
296 | 295 |
def set(self, key, value): |
297 | 296 |
self.cache[key] = value |
tests/test_api.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
... | ... | |
20 | 19 |
import json |
21 | 20 |
import random |
22 | 21 |
import uuid |
22 |
from unittest import mock |
|
23 | 23 | |
24 | 24 |
import django |
25 |
import mock |
|
26 | 25 |
import pytest |
27 | 26 |
from django.contrib.auth import get_user_model |
28 | 27 |
from django.contrib.auth.hashers import check_password |
... | ... | |
48 | 47 | |
49 | 48 |
User = get_user_model() |
50 | 49 | |
51 |
USER_ATTRIBUTES_SET = set( |
|
52 |
[ |
|
53 |
'ou', |
|
54 |
'id', |
|
55 |
'uuid', |
|
56 |
'is_staff', |
|
57 |
'is_superuser', |
|
58 |
'first_name', |
|
59 |
'first_name_verified', |
|
60 |
'last_name', |
|
61 |
'last_name_verified', |
|
62 |
'date_joined', |
|
63 |
'last_login', |
|
64 |
'username', |
|
65 |
'password', |
|
66 |
'email', |
|
67 |
'is_active', |
|
68 |
'modified', |
|
69 |
'email_verified', |
|
70 |
'last_account_deletion_alert', |
|
71 |
'deactivation', |
|
72 |
'deactivation_reason', |
|
73 |
] |
|
74 |
) |
|
50 |
USER_ATTRIBUTES_SET = { |
|
51 |
'ou', |
|
52 |
'id', |
|
53 |
'uuid', |
|
54 |
'is_staff', |
|
55 |
'is_superuser', |
|
56 |
'first_name', |
|
57 |
'first_name_verified', |
|
58 |
'last_name', |
|
59 |
'last_name_verified', |
|
60 |
'date_joined', |
|
61 |
'last_login', |
|
62 |
'username', |
|
63 |
'password', |
|
64 |
'email', |
|
65 |
'is_active', |
|
66 |
'modified', |
|
67 |
'email_verified', |
|
68 |
'last_account_deletion_alert', |
|
69 |
'deactivation', |
|
70 |
'deactivation_reason', |
|
71 |
} |
|
75 | 72 | |
76 | 73 | |
77 | 74 |
def test_api_user_simple(logged_app): |
... | ... | |
86 | 83 | |
87 | 84 |
Attribute.objects.create(kind='birthdate', name='birthdate', label='birthdate', required=True) |
88 | 85 |
user = User.objects.create( |
89 |
ou=ou, username='john.doe', first_name=u'Jôhn', last_name=u'Doe', email='john.doe@example.net'
|
|
86 |
ou=ou, username='john.doe', first_name='Jôhn', last_name='Doe', email='john.doe@example.net'
|
|
90 | 87 |
) |
91 | 88 |
user.attributes.birthdate = datetime.date(2019, 2, 2) |
92 | 89 |
user.set_password('password') |
... | ... | |
111 | 108 |
response = client.get('/api/user/', HTTP_ORIGIN='http://testserver') |
112 | 109 |
data = json.loads(force_text(response.content)) |
113 | 110 |
assert isinstance(data, dict) |
114 |
assert set(data.keys()) == set( |
|
115 |
[ |
|
116 |
'uuid', |
|
117 |
'username', |
|
118 |
'first_name', |
|
119 |
'ou__slug', |
|
120 |
'ou__uuid', |
|
121 |
'ou__name', |
|
122 |
'last_name', |
|
123 |
'email', |
|
124 |
'roles', |
|
125 |
'services', |
|
126 |
'is_superuser', |
|
127 |
'ou', |
|
128 |
'birthdate', |
|
129 |
] |
|
130 |
) |
|
111 |
assert set(data.keys()) == { |
|
112 |
'uuid', |
|
113 |
'username', |
|
114 |
'first_name', |
|
115 |
'ou__slug', |
|
116 |
'ou__uuid', |
|
117 |
'ou__name', |
|
118 |
'last_name', |
|
119 |
'email', |
|
120 |
'roles', |
|
121 |
'services', |
|
122 |
'is_superuser', |
|
123 |
'ou', |
|
124 |
'birthdate', |
|
125 |
} |
|
131 | 126 |
assert data['uuid'] == user.uuid |
132 | 127 |
assert data['username'] == user.username |
133 | 128 |
assert data['first_name'] == user.first_name |
... | ... | |
142 | 137 |
assert isinstance(data['roles'], list) |
143 | 138 |
assert len(data['roles']) == 2 |
144 | 139 |
for role in data['roles']: |
145 |
assert set(role.keys()) == set( |
|
146 |
['uuid', 'name', 'slug', 'is_admin', 'is_service', 'ou__uuid', 'ou__name', 'ou__slug'] |
|
147 |
) |
|
140 |
assert set(role.keys()) == { |
|
141 |
'uuid', |
|
142 |
'name', |
|
143 |
'slug', |
|
144 |
'is_admin', |
|
145 |
'is_service', |
|
146 |
'ou__uuid', |
|
147 |
'ou__name', |
|
148 |
'ou__slug', |
|
149 |
} |
|
148 | 150 |
assert ( |
149 | 151 |
role['uuid'] == role1.uuid |
150 | 152 |
and role['name'] == role1.name |
... | ... | |
168 | 170 |
assert isinstance(data['services'], list) |
169 | 171 |
assert len(data['services']) == 1 |
170 | 172 |
s = data['services'][0] |
171 |
assert set(s.keys()) == set(['name', 'slug', 'ou', 'ou__name', 'ou__slug', 'ou__uuid', 'roles'])
|
|
173 |
assert set(s.keys()) == {'name', 'slug', 'ou', 'ou__name', 'ou__slug', 'ou__uuid', 'roles'}
|
|
172 | 174 |
assert s['name'] == service.name |
173 | 175 |
assert s['slug'] == service.slug |
174 | 176 |
assert s['ou'] == ou.name |
... | ... | |
178 | 180 |
assert isinstance(s['roles'], list) |
179 | 181 |
assert len(s['roles']) == 2 |
180 | 182 |
for role in s['roles']: |
181 |
assert set(role.keys()) == set( |
|
182 |
['uuid', 'name', 'slug', 'is_admin', 'is_service', 'ou__uuid', 'ou__name', 'ou__slug'] |
|
183 |
) |
|
183 |
assert set(role.keys()) == { |
|
184 |
'uuid', |
|
185 |
'name', |
|
186 |
'slug', |
|
187 |
'is_admin', |
|
188 |
'is_service', |
|
189 |
'ou__uuid', |
|
190 |
'ou__name', |
|
191 |
'ou__slug', |
|
192 |
} |
|
184 | 193 |
assert ( |
185 | 194 |
role['uuid'] == role1.uuid |
186 | 195 |
and role['name'] == role1.name |
... | ... | |
206 | 215 |
app.authorization = ('Basic', (user.username, user.username)) |
207 | 216 |
resp = app.get('/api/users/') |
208 | 217 |
assert isinstance(resp.json, dict) |
209 |
assert set(['previous', 'next', 'results']) == set(resp.json.keys())
|
|
218 |
assert {'previous', 'next', 'results'} == set(resp.json.keys())
|
|
210 | 219 |
assert resp.json['previous'] is None |
211 | 220 |
assert resp.json['next'] is None |
212 | 221 | |
... | ... | |
217 | 226 |
simple_role.members.add(user) |
218 | 227 |
resp = app.get(url) |
219 | 228 |
assert isinstance(resp.json, dict) |
220 |
assert set(['previous', 'next', 'results']) == set(resp.json.keys())
|
|
229 |
assert {'previous', 'next', 'results'} == set(resp.json.keys())
|
|
221 | 230 |
assert resp.json['previous'] is None |
222 | 231 |
assert resp.json['next'] is None |
223 | 232 | |
... | ... | |
237 | 246 |
'email_verified': True, |
238 | 247 |
} |
239 | 248 |
headers = basic_authorization_header(admin) |
240 |
resp = app.put_json( |
|
241 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200 |
|
242 |
) |
|
249 |
resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200) |
|
243 | 250 |
user = User.objects.get(id=simple_user.id) |
244 | 251 |
assert user.email_verified |
245 | 252 |
assert resp.json['email_verified'] |
... | ... | |
249 | 256 |
user.email = 'johnny.doeny@foo.bar' |
250 | 257 |
user.save() |
251 | 258 | |
252 |
resp = app.patch_json( |
|
253 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200 |
|
254 |
) |
|
259 |
resp = app.patch_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200) |
|
255 | 260 |
user = User.objects.get(id=simple_user.id) |
256 | 261 |
assert user.email_verified |
257 | 262 |
assert resp.json['email_verified'] |
... | ... | |
271 | 276 |
'last_name': 'Doeny', |
272 | 277 |
} |
273 | 278 |
headers = basic_authorization_header(admin) |
274 |
resp = app.put_json( |
|
275 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200 |
|
276 |
) |
|
279 |
resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200) |
|
277 | 280 |
user = User.objects.get(id=simple_user.id) |
278 | 281 |
assert not user.email_verified |
279 | 282 |
assert not resp.json['email_verified'] |
... | ... | |
282 | 285 |
user.email = 'johnny.doeny@foo.bar' |
283 | 286 |
user.save() |
284 | 287 | |
285 |
resp = app.patch_json( |
|
286 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200 |
|
287 |
) |
|
288 |
resp = app.patch_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200) |
|
288 | 289 |
user = User.objects.get(id=simple_user.id) |
289 | 290 |
assert not user.email_verified |
290 | 291 |
assert not resp.json['email_verified'] |
... | ... | |
305 | 306 |
'last_name': 'Doeny', |
306 | 307 |
} |
307 | 308 |
headers = basic_authorization_header(admin) |
308 |
resp = app.put_json( |
|
309 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200 |
|
310 |
) |
|
309 |
resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200) |
|
311 | 310 |
user = User.objects.get(id=simple_user.id) |
312 | 311 | |
313 |
resp = app.patch_json( |
|
314 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200 |
|
315 |
) |
|
312 |
resp = app.patch_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200) |
|
316 | 313 | |
317 | 314 | |
318 | 315 |
def test_api_users_create_with_email_verified(settings, app, admin): |
... | ... | |
359 | 356 |
'email': 'john.doe@nowhere.null', |
360 | 357 |
} |
361 | 358 |
headers = basic_authorization_header(admin) |
362 |
resp = app.post_json( |
|
363 |
'/api/users/{}/email/'.format(simple_user.uuid), params=payload, headers=headers, status=200 |
|
364 |
) |
|
359 |
resp = app.post_json(f'/api/users/{simple_user.uuid}/email/', params=payload, headers=headers, status=200) |
|
365 | 360 |
user = User.objects.get(id=simple_user.id) |
366 | 361 |
assert not user.email_verified |
367 | 362 | |
... | ... | |
407 | 402 | |
408 | 403 |
resp = app.get('/api/users/?service-ou=default&service-slug=service1') |
409 | 404 |
assert len(resp.json['results']) == 2 |
410 |
assert set(user['username'] for user in resp.json['results']) == set(['user1', 'user2'])
|
|
405 |
assert {user['username'] for user in resp.json['results']} == {'user1', 'user2'}
|
|
411 | 406 | |
412 | 407 |
resp = app.get('/api/users/?service-ou=default&service-slug=service2') |
413 | 408 |
assert len(resp.json['results']) == 4 |
... | ... | |
442 | 437 | |
443 | 438 |
resp = app.get(url + '?service-ou=default&service-slug=service1') |
444 | 439 |
assert len(resp.json['results']) == 2 |
445 |
assert set(user['username'] for user in resp.json['results']) == set(['user1', 'user2'])
|
|
440 |
assert {user['username'] for user in resp.json['results']} == {'user1', 'user2'}
|
|
446 | 441 | |
447 | 442 |
resp = app.get(url + '?service-ou=default&service-slug=service2') |
448 | 443 |
assert len(resp.json['results']) == 4 |
... | ... | |
495 | 490 |
payload['ou'] = api_user.ou.slug |
496 | 491 |
resp = app.post_json('/api/users/', params=payload, status=400) |
497 | 492 |
assert resp.json['result'] == 0 |
498 |
assert set(['first_name', 'last_name']) == set(resp.json['errors'])
|
|
493 |
assert {'first_name', 'last_name'} == set(resp.json['errors'])
|
|
499 | 494 |
settings.A2_API_USERS_REQUIRED_FIELDS = ['email'] |
500 | 495 |
if api_user.is_superuser or hasattr(api_user, 'oidc_client') or api_user.roles.exists(): |
501 | 496 |
status = 201 |
... | ... | |
524 | 519 | |
525 | 520 |
resp = app.post_json('/api/users/', params=payload, status=status) |
526 | 521 |
if api_user.is_superuser or api_user.roles.exists(): |
527 |
assert (USER_ATTRIBUTES_SET | set(['title', 'title_verified'])) == set(resp.json)
|
|
522 |
assert (USER_ATTRIBUTES_SET | {'title', 'title_verified'}) == set(resp.json)
|
|
528 | 523 |
assert resp.json['first_name'] == payload['first_name'] |
529 | 524 |
assert resp.json['last_name'] == payload['last_name'] |
530 | 525 |
assert resp.json['email'] == payload['email'] |
... | ... | |
584 | 579 | |
585 | 580 |
resp = app.post_json('/api/users/', params=payload, status=status) |
586 | 581 |
if api_user.is_superuser or api_user.roles.exists(): |
587 |
assert (USER_ATTRIBUTES_SET | set(['title', 'title_verified'])) == set(resp.json)
|
|
582 |
assert (USER_ATTRIBUTES_SET | {'title', 'title_verified'}) == set(resp.json)
|
|
588 | 583 |
user = get_user_model().objects.get(pk=resp.json['id']) |
589 | 584 |
assert AttributeValue.objects.with_owner(user).filter(verified=True).count() == 3 |
590 | 585 |
assert AttributeValue.objects.with_owner(user).filter(verified=False).count() == 0 |
... | ... | |
725 | 720 |
else: |
726 | 721 |
status = 403 |
727 | 722 | |
728 |
resp = app.get('/api/roles/{0}/members/{1}/'.format(role.uuid, member.uuid), status=status)
|
|
723 |
resp = app.get(f'/api/roles/{role.uuid}/members/{member.uuid}/', status=status)
|
|
729 | 724 | |
730 | 725 |
if member.username == 'fake' or role.name == 'fake': |
731 | 726 |
assert resp.json == {'result': 0, 'errors': {'detail': 'Not found.'}} |
732 | 727 |
elif status == 404: |
733 | 728 |
assert resp.json == {'result': 0, 'errors': {'detail': 'Not found.'}} |
734 | 729 |
member.roles.add(role) |
735 |
resp = app.get('/api/roles/{0}/members/{1}/'.format(role.uuid, member.uuid))
|
|
730 |
resp = app.get(f'/api/roles/{role.uuid}/members/{member.uuid}/')
|
|
736 | 731 |
assert resp.json['uuid'] == member.uuid |
737 | 732 |
assert USER_ATTRIBUTES_SET == set(resp.json) |
738 | 733 |
else: |
... | ... | |
767 | 762 |
# api call with nested users |
768 | 763 |
resp = app.get(url, params={'nested': 'true'}) |
769 | 764 |
assert resp.json['username'] == 'admin.ou1' |
770 |
assert USER_ATTRIBUTES_SET | set(['birthdate', 'birthdate_verified']) == set(resp.json)
|
|
765 |
assert USER_ATTRIBUTES_SET | {'birthdate', 'birthdate_verified'} == set(resp.json)
|
|
771 | 766 | |
772 | 767 | |
773 | 768 |
def test_api_role_add_member(app, api_user, role, member): |
... | ... | |
782 | 777 |
else: |
783 | 778 |
status = 403 |
784 | 779 | |
785 |
resp = app.post_json('/api/roles/{0}/members/{1}/'.format(role.uuid, member.uuid), status=status)
|
|
780 |
resp = app.post_json(f'/api/roles/{role.uuid}/members/{member.uuid}/', status=status)
|
|
786 | 781 |
if status == 404: |
787 | 782 |
pass |
788 | 783 |
elif authorized: |
... | ... | |
812 | 807 |
else: |
813 | 808 |
status = 403 |
814 | 809 | |
815 |
resp = app.delete_json('/api/roles/{0}/members/{1}/'.format(role.uuid, member.uuid), status=status)
|
|
810 |
resp = app.delete_json(f'/api/roles/{role.uuid}/members/{member.uuid}/', status=status)
|
|
816 | 811 | |
817 | 812 |
if status == 404: |
818 | 813 |
pass |
819 | 814 |
elif authorized: |
820 | 815 |
assert resp.json['result'] == 1 |
821 | 816 |
assert resp.json['detail'] == 'User successfully removed from role' |
822 |
resp = app.get('/api/roles/{0}/members/{1}/'.format(role.uuid, member.uuid), status=404)
|
|
817 |
resp = app.get(f'/api/roles/{role.uuid}/members/{member.uuid}/', status=404)
|
|
823 | 818 |
assert resp.json == {'result': 0, 'errors': {'detail': 'Not found.'}} |
824 | 819 |
assert_event( |
825 | 820 |
'manager.role.membership.removal', |
... | ... | |
852 | 847 |
for m in [member, member_rando2, member_rando2]: # test no duplicate |
853 | 848 |
payload['data'].append({"uuid": m.uuid}) |
854 | 849 | |
855 |
resp = app.post_json( |
|
856 |
'/api/roles/{}/relationships/members/'.format(role.uuid), params=payload, status=status |
|
857 |
) |
|
850 |
resp = app.post_json(f'/api/roles/{role.uuid}/relationships/members/', params=payload, status=status) |
|
858 | 851 | |
859 | 852 |
if status in (400, 404): |
860 | 853 |
pass |
... | ... | |
894 | 887 |
for m in [member, member_rando2, member_rando2]: # test no duplicate |
895 | 888 |
payload['data'].append({"uuid": m.uuid}) |
896 | 889 | |
897 |
resp = app.delete_json( |
|
898 |
'/api/roles/{}/relationships/members/'.format(role.uuid), params=payload, status=status |
|
899 |
) |
|
890 |
resp = app.delete_json(f'/api/roles/{role.uuid}/relationships/members/', params=payload, status=status) |
|
900 | 891 | |
901 | 892 |
if status in (400, 404): |
902 | 893 |
pass |
... | ... | |
940 | 931 |
for m in [member, member_rando2, member_rando2]: # test no duplicate |
941 | 932 |
payload['data'].append({"uuid": m.uuid}) |
942 | 933 | |
943 |
resp = app.put_json( |
|
944 |
'/api/roles/{}/relationships/members/'.format(role.uuid), params=payload, status=status |
|
945 |
) |
|
934 |
resp = app.put_json(f'/api/roles/{role.uuid}/relationships/members/', params=payload, status=status) |
|
946 | 935 | |
947 | 936 |
if status in (400, 404): |
948 | 937 |
pass |
... | ... | |
976 | 965 |
ou = get_default_ou() |
977 | 966 | |
978 | 967 |
user = User.objects.create( |
979 |
ou=ou, username='john.doe', first_name=u'Jôhn', last_name=u'Doe', email='john.doe@example.net'
|
|
968 |
ou=ou, username='john.doe', first_name='Jôhn', last_name='Doe', email='john.doe@example.net'
|
|
980 | 969 |
) |
981 | 970 |
user.save() |
982 | 971 | |
... | ... | |
987 | 976 |
if not api_user.has_perm('a2_rbac.manage_members_role', role): |
988 | 977 |
status = 403 |
989 | 978 | |
990 |
resp = app.put_json( |
|
991 |
'/api/roles/{}/relationships/members/'.format(role.uuid), params={'data': []}, status=status |
|
992 |
) |
|
979 |
resp = app.put_json(f'/api/roles/{role.uuid}/relationships/members/', params={'data': []}, status=status) |
|
993 | 980 |
if api_user.has_perm('a2_rbac.manage_members_role', role): |
994 | 981 |
assert len(role.members.all()) == 0 |
995 | 982 |
else: |
... | ... | |
1001 | 988 |
authorized = api_user.has_perm('a2_rbac.manage_members_role', role) |
1002 | 989 |
status = 405 if authorized else 403 |
1003 | 990 | |
1004 |
app.get('/api/roles/{}/relationships/members/'.format(role.uuid), status=status)
|
|
991 |
app.get(f'/api/roles/{role.uuid}/relationships/members/', status=status)
|
|
1005 | 992 | |
1006 | 993 | |
1007 | 994 |
def test_api_role_members_payload_missing(app, api_user, role): |
... | ... | |
1009 | 996 |
authorized = api_user.has_perm('a2_rbac.manage_members_role', role) |
1010 | 997 |
status = 400 if authorized else 403 |
1011 | 998 | |
1012 |
app.post_json('/api/roles/{}/relationships/members/'.format(role.uuid), status=status)
|
|
999 |
app.post_json(f'/api/roles/{role.uuid}/relationships/members/', status=status)
|
|
1013 | 1000 | |
1014 |
app.delete_json('/api/roles/{}/relationships/members/'.format(role.uuid), status=status)
|
|
1001 |
app.delete_json(f'/api/roles/{role.uuid}/relationships/members/', status=status)
|
|
1015 | 1002 | |
1016 |
app.put_json('/api/roles/{}/relationships/members/'.format(role.uuid), status=status)
|
|
1003 |
app.put_json(f'/api/roles/{role.uuid}/relationships/members/', status=status)
|
|
1017 | 1004 | |
1018 | 1005 | |
1019 | 1006 |
def test_api_role_members_wrong_payload_types(app, superuser, role_random, member_rando2): |
... | ... | |
1021 | 1008 | |
1022 | 1009 |
payload = [{"data": [{'uuid': member_rando2.uuid}]}] |
1023 | 1010 | |
1024 |
resp = app.post_json( |
|
1025 |
'/api/roles/{}/relationships/members/'.format(role_random.uuid), params=payload, status=400 |
|
1026 |
) |
|
1011 |
resp = app.post_json(f'/api/roles/{role_random.uuid}/relationships/members/', params=payload, status=400) |
|
1027 | 1012 | |
1028 | 1013 |
assert resp.json['result'] == 0 |
1029 | 1014 |
assert resp.json['errors'] == ['Payload must be a dictionary'] |
1030 | 1015 | |
1031 | 1016 |
payload = {"data": [[member_rando2.uuid]]} |
1032 | 1017 | |
1033 |
resp = app.post_json( |
|
1034 |
'/api/roles/{}/relationships/members/'.format(role_random.uuid), params=payload, status=400 |
|
1035 |
) |
|
1018 |
resp = app.post_json(f'/api/roles/{role_random.uuid}/relationships/members/', params=payload, status=400) |
|
1036 | 1019 | |
1037 | 1020 |
assert resp.json['result'] == 0 |
1038 | 1021 |
assert resp.json['errors'] == ["List elements of the 'data' dict entry must be dictionaries"] |
1039 | 1022 | |
1040 | 1023 |
payload = {"data": [member_rando2.uuid]} |
1041 | 1024 | |
1042 |
resp = app.post_json( |
|
1043 |
'/api/roles/{}/relationships/members/'.format(role_random.uuid), params=payload, status=400 |
|
1044 |
) |
|
1025 |
resp = app.post_json(f'/api/roles/{role_random.uuid}/relationships/members/', params=payload, status=400) |
|
1045 | 1026 | |
1046 | 1027 |
assert resp.json['result'] == 0 |
1047 | 1028 |
assert resp.json['errors'] == ["List elements of the 'data' dict entry must be dictionaries"] |
... | ... | |
1219 | 1200 |
payload = {'username': 'whatever'} |
1220 | 1201 |
resp = app.post_json(reverse('a2-api-check-password'), params=payload, status=400) |
1221 | 1202 |
assert resp.json['result'] == 0 |
1222 |
assert resp.json['errors'] == {u'password': [u'This field is required.']}
|
|
1203 |
assert resp.json['errors'] == {'password': ['This field is required.']}
|
|
1223 | 1204 |
# test with invalid credentials |
1224 | 1205 |
payload = {'username': 'whatever', 'password': 'password'} |
1225 | 1206 |
resp = app.post_json(reverse('a2-api-check-password'), params=payload, status=200) |
... | ... | |
1322 | 1303 | |
1323 | 1304 |
def test_api_delete_role(app, admin_ou1, role_ou1): |
1324 | 1305 |
app.authorization = ('Basic', (admin_ou1.username, admin_ou1.username)) |
1325 |
app.delete('/api/roles/{}/'.format(role_ou1.uuid))
|
|
1306 |
app.delete(f'/api/roles/{role_ou1.uuid}/')
|
|
1326 | 1307 |
assert not len(Role.objects.filter(slug='role_ou1')) |
1327 | 1308 |
assert_event('manager.role.deletion', user=admin_ou1, api=True, role_name=role_ou1.name) |
1328 | 1309 | |
1329 | 1310 | |
1330 | 1311 |
def test_api_delete_role_unauthorized(app, simple_user, role_ou1): |
1331 | 1312 |
app.authorization = ('Basic', (simple_user.username, simple_user.username)) |
1332 |
app.delete('/api/roles/{}/'.format(role_ou1.uuid), status=404)
|
|
1313 |
app.delete(f'/api/roles/{role_ou1.uuid}/', status=404)
|
|
1333 | 1314 |
assert len(Role.objects.filter(slug='role_ou1')) |
1334 | 1315 | |
1335 | 1316 | |
... | ... | |
1339 | 1320 |
role_data = { |
1340 | 1321 |
'slug': 'updated-role', |
1341 | 1322 |
} |
1342 |
app.patch_json('/api/roles/{}/'.format(role_ou1.uuid), params=role_data)
|
|
1323 |
app.patch_json(f'/api/roles/{role_ou1.uuid}/', params=role_data)
|
|
1343 | 1324 |
assert_event('manager.role.edit', user=admin_ou1, api=True, role_name=role_ou1.name) |
1344 | 1325 | |
1345 | 1326 |
# The role API won't change the organizational unit attribute: |
... | ... | |
1354 | 1335 |
role_data = { |
1355 | 1336 |
'slug': 'updated-role', |
1356 | 1337 |
} |
1357 |
app.patch_json('/api/roles/{}/'.format(role_ou1.uuid), params=role_data, status=404)
|
|
1338 |
app.patch_json(f'/api/roles/{role_ou1.uuid}/', params=role_data, status=404)
|
|
1358 | 1339 |
role_ou1.refresh_from_db() |
1359 | 1340 |
assert role_ou1.slug == 'role_ou1' |
1360 | 1341 |
assert not len(Role.objects.filter(slug='updated-role')) |
... | ... | |
1364 | 1345 |
app.authorization = ('Basic', (admin_ou1.username, admin_ou1.username)) |
1365 | 1346 | |
1366 | 1347 |
role_data = {'name': 'updated-role', 'slug': 'updated-role', 'ou': 'ou2'} |
1367 |
app.put_json('/api/roles/{}/'.format(role_ou1.uuid), params=role_data)
|
|
1348 |
app.put_json(f'/api/roles/{role_ou1.uuid}/', params=role_data)
|
|
1368 | 1349 |
role_ou1.refresh_from_db() |
1369 | 1350 |
assert role_ou1.name == 'updated-role' |
1370 | 1351 |
assert role_ou1.slug == 'updated-role' |
... | ... | |
1375 | 1356 |
def test_api_put_role_unauthorized(app, simple_user, role_ou1, ou1): |
1376 | 1357 |
app.authorization = ('Basic', (simple_user.username, simple_user.username)) |
1377 | 1358 |
role_data = {'name': 'updated-role', 'slug': 'updated-role', 'ou': 'ou2'} |
1378 |
app.put_json('/api/roles/{}/'.format(role_ou1.uuid), params=role_data, status=404)
|
|
1359 |
app.put_json(f'/api/roles/{role_ou1.uuid}/', params=role_data, status=404)
|
|
1379 | 1360 |
role_ou1.refresh_from_db() |
1380 | 1361 |
assert role_ou1.name == 'role_ou1' |
1381 | 1362 |
assert role_ou1.slug == 'role_ou1' |
... | ... | |
1508 | 1489 | |
1509 | 1490 |
def test_api_get_role_description(app, admin_rando_role, role_random): |
1510 | 1491 |
app.authorization = ('Basic', (admin_rando_role.username, admin_rando_role.username)) |
1511 |
resp = app.get('/api/roles/{}/'.format(role_random.uuid))
|
|
1492 |
resp = app.get(f'/api/roles/{role_random.uuid}/')
|
|
1512 | 1493 | |
1513 | 1494 |
assert resp.json['slug'] == 'rando' |
1514 | 1495 |
assert resp.json['ou'] == 'ou_rando' |
... | ... | |
1554 | 1535 |
resp = app.get(url) |
1555 | 1536 |
assert len(resp.json['results']) > 0 |
1556 | 1537 |
for user_dict in resp.json['results']: |
1557 |
assert USER_ATTRIBUTES_SET | set(['birthdate', 'birthdate_verified']) == set(user_dict)
|
|
1538 |
assert USER_ATTRIBUTES_SET | {'birthdate', 'birthdate_verified'} == set(user_dict)
|
|
1558 | 1539 |
assert [x['username'] for x in resp.json['results']] == ['john.doe'] |
1559 | 1540 | |
1560 | 1541 |
# api call with nested users |
... | ... | |
1853 | 1834 | |
1854 | 1835 |
# update from missing value to blank field fails |
1855 | 1836 |
payload['last_name'] = '' |
1856 |
resp = app.put_json( |
|
1857 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=400 |
|
1858 |
) |
|
1837 |
resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=400) |
|
1859 | 1838 |
assert resp.json['result'] == 0 |
1860 | 1839 |
assert resp.json['errors']['last_name'] == ['This field may not be blank.'] |
1861 | 1840 | |
1862 | 1841 |
# update with value pass |
1863 | 1842 |
payload['last_name'] = 'Foobar' |
1864 |
resp = app.put_json( |
|
1865 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200 |
|
1866 |
) |
|
1843 |
resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200) |
|
1867 | 1844 |
user = User.objects.get(id=simple_user.id) |
1868 | 1845 |
assert user.last_name == 'Foobar' |
1869 | 1846 | |
1870 | 1847 |
# update from non-empty value to blank fails |
1871 | 1848 |
payload['last_name'] = '' |
1872 |
resp = app.put_json( |
|
1873 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=400 |
|
1874 |
) |
|
1849 |
resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=400) |
|
1875 | 1850 |
assert resp.json['result'] == 0 |
1876 | 1851 |
assert resp.json['errors']['last_name'] == ['This field may not be blank.'] |
1877 | 1852 | |
... | ... | |
1901 | 1876 |
payload['prefered_color'] = '' |
1902 | 1877 |
payload['date'] = '' |
1903 | 1878 |
payload['birthdate'] = '' |
1904 |
resp = app.put_json( |
|
1905 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=400 |
|
1906 |
) |
|
1879 |
resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=400) |
|
1907 | 1880 |
assert resp.json['result'] == 0 |
1908 | 1881 |
assert resp.json['errors']['prefered_color'] == ['This field may not be blank.'] |
1909 | 1882 |
assert resp.json['errors']['date'] == ['This field may not be blank.'] |
... | ... | |
1913 | 1886 |
payload['prefered_color'] = '?' * 257 |
1914 | 1887 |
payload['date'] = '0000-00-00' |
1915 | 1888 |
payload['birthdate'] = '1899-12-31' |
1916 |
resp = app.put_json( |
|
1917 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=400 |
|
1918 |
) |
|
1889 |
resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=400) |
|
1919 | 1890 |
assert resp.json['result'] == 0 |
1920 | 1891 |
assert resp.json['errors']['prefered_color'] == ['Ensure this field has no more than 256 characters.'] |
1921 | 1892 |
assert any(error.startswith('Date has wrong format.') for error in resp.json['errors']['date']) |
... | ... | |
1928 | 1899 |
payload['prefered_color'] = 'blue' |
1929 | 1900 |
payload['date'] = '1515-01-15' |
1930 | 1901 |
payload['birthdate'] = '1900-02-22' |
1931 |
resp = app.put_json( |
|
1932 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200 |
|
1933 |
) |
|
1902 |
resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200) |
|
1934 | 1903 |
assert_event('manager.user.profile.edit', user=admin, api=True, new=payload) |
1935 | 1904 | |
1936 | 1905 |
# value are properly returned on a get |
1937 |
resp = app.get('/api/users/{}/'.format(simple_user.uuid), headers=headers, status=200)
|
|
1906 |
resp = app.get(f'/api/users/{simple_user.uuid}/', headers=headers, status=200)
|
|
1938 | 1907 |
assert resp.json['prefered_color'] == 'blue' |
1939 | 1908 |
assert resp.json['date'] == '1515-01-15' |
1940 | 1909 |
assert resp.json['birthdate'] == '1900-02-22' |
... | ... | |
1953 | 1922 |
'last_name': 'Doe', |
1954 | 1923 |
} |
1955 | 1924 |
headers = basic_authorization_header(admin) |
1956 |
resp = app.put_json( |
|
1957 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200 |
|
1958 |
) |
|
1959 |
resp = app.get('/api/users/{}/'.format(simple_user.uuid), headers=headers, status=200) |
|
1925 |
resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200) |
|
1926 |
resp = app.get(f'/api/users/{simple_user.uuid}/', headers=headers, status=200) |
|
1960 | 1927 |
payload['prefered_color'] = None |
1961 | 1928 |
payload['date'] = None |
1962 | 1929 |
payload['birthdate'] = None |
... | ... | |
1964 | 1931 |
payload['prefered_color'] = '' |
1965 | 1932 |
payload['date'] = '' |
1966 | 1933 |
payload['birthdate'] = '' |
1967 |
resp = app.put_json( |
|
1968 |
'/api/users/{}/'.format(simple_user.uuid), params=payload, headers=headers, status=200 |
|
1969 |
) |
|
1970 |
resp = app.get('/api/users/{}/'.format(simple_user.uuid), headers=headers, status=200) |
|
1934 |
resp = app.put_json(f'/api/users/{simple_user.uuid}/', params=payload, headers=headers, status=200) |
|
1935 |
resp = app.get(f'/api/users/{simple_user.uuid}/', headers=headers, status=200) |
|
1971 | 1936 |
payload['prefered_color'] = None |
1972 | 1937 |
payload['date'] = None |
1973 | 1938 |
payload['birthdate'] = None |
... | ... | |
2253 | 2218 |
user2 = User.objects.create(username='foo2', email=email) |
2254 | 2219 | |
2255 | 2220 |
app.authorization = ('Basic', (admin.username, admin.username)) |
2256 |
resp = app.get('/api/users/?email={}'.format(email))
|
|
2221 |
resp = app.get(f'/api/users/?email={email}')
|
|
2257 | 2222 |
assert len(resp.json['results']) == 1 |
2258 | 2223 | |
2259 | 2224 |
payload = { |
... | ... | |
2265 | 2230 |
headers = basic_authorization_header(admin) |
2266 | 2231 |
app.post_json('/api/users/', headers=headers, params=payload, status=201) |
2267 | 2232 | |
2268 |
resp = app.get('/api/users/?email={}'.format(email))
|
|
2233 |
resp = app.get(f'/api/users/?email={email}')
|
|
2269 | 2234 |
assert len(resp.json['results']) == 2 |
2270 | 2235 | |
2271 | 2236 |
user2.delete() |
2272 |
resp = app.get('/api/users/?email={}'.format(email))
|
|
2237 |
resp = app.get(f'/api/users/?email={email}')
|
|
2273 | 2238 |
assert len(resp.json['results']) == 1 |
2274 | 2239 | |
2275 | 2240 |
settings.A2_EMAIL_IS_UNIQUE = True |
... | ... | |
2325 | 2290 | |
2326 | 2291 |
def test_api_users_delete(settings, app, admin, simple_user): |
2327 | 2292 |
headers = basic_authorization_header(admin) |
2328 |
resp = app.delete_json('/api/users/{}/'.format(simple_user.uuid), headers=headers)
|
|
2293 |
resp = app.delete_json(f'/api/users/{simple_user.uuid}/', headers=headers)
|
|
2329 | 2294 |
assert not User.objects.filter(pk=simple_user.pk).exists() |
2330 | 2295 |
assert_event('manager.user.deletion', user=admin, api=True) |
2331 | 2296 |
tests/test_attribute_kinds.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
tests/test_auth_oidc.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2020 Entr'ouvert |
4 | 3 |
# |
... | ... | |
515 | 514 |
with oidc_provider_mock(oidc_provider, oidc_provider_jwkset, code, nonce=nonce): |
516 | 515 |
response = app.get(login_callback_url(oidc_provider), params={'code': code, 'state': state}) |
517 | 516 |
assert len(hooks.auth_oidc_backend_modify_user) == 1 |
518 |
assert set(hooks.auth_oidc_backend_modify_user[0]['kwargs']) >= set( |
|
519 |
['user', 'provider', 'user_info', 'id_token', 'access_token'] |
|
520 |
) |
|
517 |
assert set(hooks.auth_oidc_backend_modify_user[0]['kwargs']) >= { |
|
518 |
'user', |
|
519 |
'provider', |
|
520 |
'user_info', |
|
521 |
'id_token', |
|
522 |
'access_token', |
|
523 |
} |
|
521 | 524 |
assert urllib.parse.urlparse(response['Location']).path == '/admin/' |
522 | 525 |
assert User.objects.count() == 1 |
523 | 526 |
user = User.objects.get() |
... | ... | |
697 | 700 | |
698 | 701 |
with pytest.raises(IDTokenError): |
699 | 702 |
with utils.check_log(caplog, 'missing field'): |
700 |
token = IDToken( |
|
701 |
'{}.{}.{}'.format(_header(oidc_provider), erroneous_payload, _signature(oidc_provider)) |
|
702 |
) |
|
703 |
token = IDToken(f'{_header(oidc_provider)}.{erroneous_payload}.{_signature(oidc_provider)}') |
|
703 | 704 |
token.deserialize(oidc_provider) |
704 | 705 | |
705 | 706 |
tests/test_commands.py | ||
---|---|---|
203 | 203 |
ldif = tmpdir.join('some.ldif') |
204 | 204 |
ldif.ensure() |
205 | 205 | |
206 |
class MockPArser(object):
|
|
206 |
class MockPArser: |
|
207 | 207 |
def __init__(self, *args, **kwargs): |
208 | 208 |
self.users = [] |
209 | 209 |
assert len(args) == 1 |
... | ... | |
219 | 219 |
call_command('load-ldif', ldif.strpath, result='result', extra_attribute={'ldap_attr': 'first_name'}) |
220 | 220 | |
221 | 221 |
# test ExtraAttributeAction |
222 |
class MockPArser(object):
|
|
222 |
class MockPArser: |
|
223 | 223 |
def __init__(self, *args, **kwargs): |
224 | 224 |
self.users = [] |
225 | 225 |
assert len(args) == 1 |
tests/test_crypto.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
tests/test_csv_import.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
... | ... | |
15 | 14 |
# You should have received a copy of the GNU Affero General Public License |
16 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 16 | |
18 |
from __future__ import unicode_literals |
|
19 | 17 | |
20 | 18 |
import codecs |
21 | 19 |
import io |
... | ... | |
89 | 87 | |
90 | 88 |
def test_bad_csv_encoding(profile): |
91 | 89 |
importer = CsvImporter() |
92 |
assert not importer.run(u'é'.encode('utf-8'), 'ascii')
|
|
90 |
assert not importer.run('é'.encode(), 'ascii')
|
|
93 | 91 |
assert importer.error == Error('bad-encoding') |
94 | 92 | |
95 | 93 | |
... | ... | |
173 | 171 | |
174 | 172 | |
175 | 173 |
def test_bom_character(profile, user_csv_importer_factory): |
176 |
content = codecs.BOM_UTF8 + 'email key,first_name\ntest@entrouvert.org,hop'.encode('utf-8')
|
|
174 |
content = codecs.BOM_UTF8 + b'email key,first_name\ntest@entrouvert.org,hop'
|
|
177 | 175 |
file_content = io.BytesIO(content) |
178 | 176 |
importer = UserCsvImporter() |
179 | 177 |
assert importer.run(file_content, 'utf-8-sig') |
tests/test_custom_user.py | ||
---|---|---|
38 | 38 | |
39 | 39 |
user1 = User.objects.create(username='user') |
40 | 40 |
user1.roles.add(rchild1) |
41 |
assert set([r.id for r in user1.roles_and_parents()]) == set([rchild1.id, rparent1.id, rparent2.id])
|
|
41 |
assert {r.id for r in user1.roles_and_parents()} == {rchild1.id, rparent1.id, rparent2.id}
|
|
42 | 42 |
for r in user1.roles_and_parents(): |
43 | 43 |
if r.id == rchild1.id: |
44 | 44 |
assert r.member == [user1] |
... | ... | |
47 | 47 |
assert r.member == [] |
48 | 48 |
user1.roles.remove(rchild1) |
49 | 49 |
user1.roles.add(rchild2) |
50 |
assert set([r.id for r in user1.roles_and_parents()]) == set([rchild2.id, rparent1.id, rparent2.id])
|
|
50 |
assert {r.id for r in user1.roles_and_parents()} == {rchild2.id, rparent1.id, rparent2.id}
|
|
51 | 51 |
for r in user1.roles_and_parents(): |
52 | 52 |
if r.id == rchild2.id: |
53 | 53 |
assert r.member == [user1] |
tests/test_data_transfer.py | ||
---|---|---|
70 | 70 |
assert child_role_dict['slug'] == child_role.slug |
71 | 71 |
parents = child_role_dict['parents'] |
72 | 72 |
assert len(parents) == 2 |
73 |
expected_slugs = set([parent_1_role.slug, parent_2_role.slug])
|
|
73 |
expected_slugs = {parent_1_role.slug, parent_2_role.slug}
|
|
74 | 74 |
for parent in parents: |
75 | 75 |
assert parent['slug'] in expected_slugs |
76 | 76 |
expected_slugs.remove(parent['slug']) |
tests/test_fields.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import unicode_literals |
|
18 | 17 | |
19 | 18 |
import pytest |
20 | 19 |
from django.core.exceptions import ValidationError |
tests/test_idp_cas.py | ||
---|---|---|
183 | 183 |
next_url, next_url_query = query['next'][0].split('?') |
184 | 184 |
next_url_query = urllib.parse.parse_qs(next_url_query) |
185 | 185 |
self.assertEqual(next_url, '/idp/cas/continue/') |
186 |
self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
|
|
186 |
self.assertEqual(set(next_url_query.keys()), {constants.SERVICE_PARAM, NONCE_FIELD_NAME})
|
|
187 | 187 |
self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL]) |
188 | 188 |
self.assertEqual(next_url_query[NONCE_FIELD_NAME], [ticket.ticket_id]) |
189 | 189 |
response = self.client.get(location) |
... | ... | |
240 | 240 |
next_url, next_url_query = query['next'][0].split('?') |
241 | 241 |
next_url_query = urllib.parse.parse_qs(next_url_query) |
242 | 242 |
self.assertEqual(next_url, '/idp/cas/continue/') |
243 |
self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
|
|
243 |
self.assertEqual(set(next_url_query.keys()), {constants.SERVICE_PARAM, NONCE_FIELD_NAME})
|
|
244 | 244 |
self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL]) |
245 | 245 |
self.assertEqual(next_url_query[NONCE_FIELD_NAME], [ticket.ticket_id]) |
246 | 246 |
response = self.client.get(location) |
... | ... | |
301 | 301 |
next_url, next_url_query = query['next'][0].split('?') |
302 | 302 |
next_url_query = urllib.parse.parse_qs(next_url_query) |
303 | 303 |
self.assertEqual(next_url, '/idp/cas/continue/') |
304 |
self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
|
|
304 |
self.assertEqual(set(next_url_query.keys()), {constants.SERVICE_PARAM, NONCE_FIELD_NAME})
|
|
305 | 305 |
self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL]) |
306 | 306 |
self.assertEqual(next_url_query[NONCE_FIELD_NAME], [ticket.ticket_id]) |
307 | 307 |
response = self.client.get(location) |
... | ... | |
360 | 360 |
next_url, next_url_query = query['next'][0].split('?') |
361 | 361 |
next_url_query = urllib.parse.parse_qs(next_url_query) |
362 | 362 |
self.assertEqual(next_url, '/idp/cas/continue/') |
363 |
self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
|
|
363 |
self.assertEqual(set(next_url_query.keys()), {constants.SERVICE_PARAM, NONCE_FIELD_NAME})
|
|
364 | 364 |
self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL]) |
365 | 365 |
self.assertEqual(next_url_query[NONCE_FIELD_NAME], [ticket.ticket_id]) |
366 | 366 |
response = self.client.get(location) |
... | ... | |
422 | 422 |
next_url, next_url_query = query['next'][0].split('?') |
423 | 423 |
next_url_query = urllib.parse.parse_qs(next_url_query) |
424 | 424 |
self.assertEqual(next_url, '/idp/cas/continue/') |
425 |
self.assertEqual(set(next_url_query.keys()), set([constants.SERVICE_PARAM, NONCE_FIELD_NAME]))
|
|
425 |
self.assertEqual(set(next_url_query.keys()), {constants.SERVICE_PARAM, NONCE_FIELD_NAME})
|
|
426 | 426 |
self.assertEqual(next_url_query[constants.SERVICE_PARAM], [self.URL]) |
427 | 427 |
self.assertEqual(next_url_query[NONCE_FIELD_NAME], [ticket.ticket_id]) |
428 | 428 |
response = self.client.get(location) |
tests/test_idp_saml2.py | ||
---|---|---|
1 |
# coding: utf-8 |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2020 Entr'ouvert |
4 | 3 |
# |
... | ... | |
15 | 14 |
# You should have received a copy of the GNU Affero General Public License |
16 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 16 | |
18 |
from __future__ import unicode_literals |
|
19 | 17 | |
20 | 18 |
import base64 |
21 | 19 |
import datetime |
... | ... | |
23 | 21 |
import re |
24 | 22 |
import urllib.parse |
25 | 23 |
import xml.etree.ElementTree as ET |
24 |
from unittest import mock |
|
26 | 25 | |
27 | 26 |
import lasso |
28 |
import mock |
|
29 | 27 |
import pytest |
30 | 28 |
from django.contrib.auth import REDIRECT_FIELD_NAME |
31 | 29 |
from django.core.files import File |
... | ... | |
63 | 61 |
return response.text |
64 | 62 | |
65 | 63 | |
66 |
class Raw(object):
|
|
64 |
class Raw: |
|
67 | 65 |
def __init__(self, d): |
68 | 66 |
self.__dict__.update(d) |
69 | 67 | |
... | ... | |
102 | 100 |
return user |
103 | 101 | |
104 | 102 | |
105 |
class SamlSP(object):
|
|
103 |
class SamlSP: |
|
106 | 104 |
METADATA_TPL = '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
107 | 105 |
<EntityDescriptor |
108 | 106 |
entityID="{{ base_url }}/" |
... | ... | |
298 | 296 |
login.initRequest(force_str(query_string), method) |
299 | 297 |
login.buildRequestMsg() |
300 | 298 |
response = self.app.post( |
301 |
login.msgUrl, params=force_bytes(login.msgBody), headers={'content-type': str('text/xml')}
|
|
299 |
login.msgUrl, params=force_bytes(login.msgBody), headers={'content-type': 'text/xml'}
|
|
302 | 300 |
) |
303 | 301 |
login.processResponseMsg(force_str(response.text)) |
304 | 302 |
login.acceptSso() |
305 | 303 | |
306 | 304 | |
307 |
class Scenario(object):
|
|
305 |
class Scenario: |
|
308 | 306 |
check_federation = False |
309 | 307 | |
310 | 308 |
def __init__(self, app, sp_kwargs=None, make_authn_request_kwargs=None, **kwargs): |
... | ... | |
507 | 505 |
( |
508 | 506 |
"/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name='verified_attributes']/" |
509 | 507 |
"saml:AttributeValue", |
510 |
set(['code_code', 'mobile']),
|
|
508 |
{'code_code', 'mobile'},
|
|
511 | 509 |
), |
512 | 510 |
) |
513 | 511 |
if user is not None and self.sp.admin_role in user.roles.all(): |
... | ... | |
651 | 649 |
func.nid_format, |
652 | 650 |
) |
653 | 651 |
return { |
654 |
at.name: set( |
|
655 |
[''.join(force_text(mtn.dump()) for mtn in atv.any) for atv in at.attributeValue] |
|
656 |
) |
|
652 |
at.name: {''.join(force_text(mtn.dump()) for mtn in atv.any) for atv in at.attributeValue} |
|
657 | 653 |
for at in assertion.attributeStatement[0].attribute |
658 | 654 |
} |
659 | 655 | |
... | ... | |
684 | 680 | |
685 | 681 |
# check |
686 | 682 |
assert attributes == { |
687 |
'nom': set(['Rigby']),
|
|
688 |
'prenom': set(['Éléonore']),
|
|
683 |
'nom': {'Rigby'},
|
|
684 |
'prenom': {'Éléonore'},
|
|
689 | 685 |
} |
690 | 686 | |
691 | 687 | |
... | ... | |
720 | 716 | |
721 | 717 |
# check |
722 | 718 |
assert attributes == { |
723 |
'nom': set(['Rigby']),
|
|
724 |
'prenom': set(['Éléonore', 'coucou']),
|
|
719 |
'nom': {'Rigby'},
|
|
720 |
'prenom': {'Éléonore', 'coucou'},
|
|
725 | 721 |
} |
726 | 722 | |
727 | 723 | |
... | ... | |
758 | 754 |
profile.request.extensions.any = tuple(force_str(ext) for ext in extensions) |
759 | 755 | |
760 | 756 |
login_hints = get_login_hints_extension(profile) |
761 |
assert login_hints == set(['backoffice', 'saint-machin-truc', 'toto@example.com'])
|
|
757 |
assert login_hints == {'backoffice', 'saint-machin-truc', 'toto@example.com'}
|
|
762 | 758 | |
763 | 759 | |
764 | 760 |
def test_make_edu_person_targeted_id(db, settings, rf): |
... | ... | |
809 | 805 | |
810 | 806 |
# check |
811 | 807 |
assert len(attributes) == 3 |
812 |
assert attributes['nom'] == set(['Rambo'])
|
|
813 |
assert attributes['prenom'] == set(['John'])
|
|
808 |
assert attributes['nom'] == {'Rambo'}
|
|
809 |
assert attributes['prenom'] == {'John'}
|
|
814 | 810 |
edu_name = 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10' |
815 | 811 | |
816 | 812 |
assert len(attributes[edu_name]) == 1 |
... | ... | |
842 | 838 | |
843 | 839 |
# check |
844 | 840 |
assert len(attributes) == 3 |
845 |
assert attributes['nom'] == set(['Rambo'])
|
|
846 |
assert attributes['prenom'] == set(['John'])
|
|
841 |
assert attributes['nom'] == {'Rambo'}
|
|
842 |
assert attributes['prenom'] == {'John'}
|
|
847 | 843 | |
848 | 844 |
assert len(attributes['edupersontargetedid']) == 1 |
849 | 845 |
node = lasso.Node.newFromXmlNode(force_str(list(attributes['edupersontargetedid'])[0])) |
... | ... | |
930 | 926 | |
931 | 927 |
attributes = add_attributes_all(user_ou1) |
932 | 928 |
assert attributes == { |
933 |
'a2_role_names': set(['Role of service', 'role_ou2']),
|
|
934 |
'a2_role_slugs': set(['role-of-service', 'role_ou2']),
|
|
935 |
'a2_role_uuids': set([service_role.uuid, role_ou2.uuid]),
|
|
936 |
'a2_service_ou_role_names': set(['Role of service']),
|
|
937 |
'a2_service_ou_role_slugs': set(['role-of-service']),
|
|
938 |
'a2_service_ou_role_uuids': set([service_role.uuid]),
|
|
939 |
'django_user_birthdate': set(['1970-01-01']),
|
|
940 |
'django_user_date_joined': set([str(user_ou1.date_joined)]),
|
|
941 |
'django_user_deleted': set([]),
|
|
942 |
'django_user_domain': set(['']),
|
|
943 |
'django_user_email': set(['john.doe@example.net']),
|
|
944 |
'django_user_email_verified': set(['false']),
|
|
945 |
'django_user_first_name': set(['J\xf4hn']),
|
|
946 |
'django_user_full_name': set(['J\xf4hn D\xf4e']),
|
|
947 |
'django_user_group_names': set([]),
|
|
948 |
'django_user_groups': set([]),
|
|
949 |
'django_user_id': set([str(user_ou1.id)]),
|
|
950 |
'django_user_identifier': set(['john.doe']),
|
|
951 |
'django_user_is_active': set(['true']),
|
|
952 |
'django_user_is_staff': set(['false']),
|
|
953 |
'django_user_is_superuser': set(['false']),
|
|
954 |
'django_user_last_account_deletion_alert': set([]),
|
|
955 |
'django_user_last_login': set([]),
|
|
956 |
'django_user_last_name': set(['D\xf4e']),
|
|
957 |
'django_user_modified': set([str(user_ou1.modified)]),
|
|
958 |
'django_user_ou': set([]),
|
|
959 |
'django_user_ou_name': set(['OU1']),
|
|
960 |
'django_user_ou_slug': set(['ou1']),
|
|
961 |
'django_user_ou_uuid': set([ou1.uuid]),
|
|
962 |
'django_user_password': set(['abba0b6ff456806bab66baed93e6d9c4']),
|
|
963 |
'django_user_username': set(['john.doe']),
|
|
964 |
'django_user_uuid': set([user_ou1.uuid]),
|
|
965 |
'is_admin': set(['true']),
|
|
929 |
'a2_role_names': {'Role of service', 'role_ou2'},
|
|
930 |
'a2_role_slugs': {'role-of-service', 'role_ou2'},
|
|
931 |
'a2_role_uuids': {service_role.uuid, role_ou2.uuid},
|
|
932 |
'a2_service_ou_role_names': {'Role of service'},
|
|
933 |
'a2_service_ou_role_slugs': {'role-of-service'},
|
|
934 |
'a2_service_ou_role_uuids': {service_role.uuid},
|
|
935 |
'django_user_birthdate': {'1970-01-01'},
|
|
936 |
'django_user_date_joined': {str(user_ou1.date_joined)},
|
|
937 |
'django_user_deleted': set(), |
|
938 |
'django_user_domain': {''},
|
|
939 |
'django_user_email': {'john.doe@example.net'},
|
|
940 |
'django_user_email_verified': {'false'},
|
|
941 |
'django_user_first_name': {'J\xf4hn'},
|
|
942 |
'django_user_full_name': {'J\xf4hn D\xf4e'},
|
|
943 |
'django_user_group_names': set(), |
|
944 |
'django_user_groups': set(), |
|
945 |
'django_user_id': {str(user_ou1.id)},
|
|
946 |
'django_user_identifier': {'john.doe'},
|
|
947 |
'django_user_is_active': {'true'},
|
|
948 |
'django_user_is_staff': {'false'},
|
|
949 |
'django_user_is_superuser': {'false'},
|
|
950 |
'django_user_last_account_deletion_alert': set(), |
|
951 |
'django_user_last_login': set(), |
|
952 |
'django_user_last_name': {'D\xf4e'},
|
|
953 |
'django_user_modified': {str(user_ou1.modified)},
|
|
954 |
'django_user_ou': set(), |
|
955 |
'django_user_ou_name': {'OU1'},
|
|
956 |
'django_user_ou_slug': {'ou1'},
|
|
957 |
'django_user_ou_uuid': {ou1.uuid},
|
|
958 |
'django_user_password': {'abba0b6ff456806bab66baed93e6d9c4'},
|
|
959 |
'django_user_username': {'john.doe'},
|
|
960 |
'django_user_uuid': {user_ou1.uuid},
|
|
961 |
'is_admin': {'true'},
|
|
966 | 962 |
} |
967 | 963 | |
968 | 964 |
tests/test_journal.py | ||
---|---|---|
16 | 16 | |
17 | 17 |
import random |
18 | 18 |
from datetime import datetime, timedelta |
19 |
from unittest import mock |
|
19 | 20 | |
20 |
import mock |
|
21 | 21 |
import pytest |
22 | 22 |
import pytz |
23 | 23 |
from django.contrib.auth import get_user_model |
... | ... | |
107 | 107 |
assert Event.objects.from_cursor(ev1.cursor).count() == 12 |
108 | 108 |
assert list(Event.objects.all()[ev2.cursor : 2]) == events[6:8] |
109 | 109 |
assert list(Event.objects.all()[-4 : ev2.cursor]) == events[3:7] |
110 |
assert set(Event.objects.which_references(service)[0].references) == set([service])
|
|
110 |
assert set(Event.objects.which_references(service)[0].references) == {service}
|
|
111 | 111 | |
112 | 112 |
# verify type, user and service are prefetched |
113 | 113 |
with django_assert_num_queries(3): |
tests/test_large_userbase.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
tests/test_ldap.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
... | ... | |
19 | 18 |
import os |
20 | 19 |
import time |
21 | 20 |
import urllib.parse |
21 |
from unittest import mock |
|
22 | 22 | |
23 | 23 |
import ldap |
24 |
import mock |
|
25 | 24 |
import pytest |
26 | 25 |
from django.contrib.auth import get_user_model |
27 | 26 |
from django.core import mail, management |
... | ... | |
510 | 509 |
'use_tls': False, |
511 | 510 |
'create_group': True, |
512 | 511 |
'group_mapping': [ |
513 |
[u'cn=group1,o=ôrga', ['Group1']],
|
|
512 |
['cn=group1,o=ôrga', ['Group1']], |
|
514 | 513 |
], |
515 | 514 |
} |
516 | 515 |
] |
... | ... | |
533 | 532 |
'use_tls': False, |
534 | 533 |
'create_group': True, |
535 | 534 |
'group_mapping': [ |
536 |
[u'cn=group2,o=ôrga', ['Group2']],
|
|
535 |
['cn=group2,o=ôrga', ['Group2']], |
|
537 | 536 |
], |
538 | 537 |
'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))', |
539 | 538 |
} |
... | ... | |
569 | 568 |
'/login/', {'login-password-submit': '1', 'username': USERNAME, 'password': PASS}, follow=True |
570 | 569 |
) |
571 | 570 |
assert response.context['user'].username == '%s@ldap' % USERNAME |
572 |
assert set(response.context['user'].roles.values_list('name', flat=True)) == set(['Role1', 'Role2'])
|
|
571 |
assert set(response.context['user'].roles.values_list('name', flat=True)) == {'Role1', 'Role2'}
|
|
573 | 572 | |
574 | 573 | |
575 | 574 |
def test_posix_group_to_role_mapping(slapd, settings, client, db): |
... | ... | |
642 | 641 |
'url': [slapd.ldap_url], |
643 | 642 |
'basedn': 'o=ôrga', |
644 | 643 |
'use_tls': False, |
645 |
'groupsu': [u'cn=group1,o=ôrga'],
|
|
644 |
'groupsu': ['cn=group1,o=ôrga'], |
|
646 | 645 |
} |
647 | 646 |
] |
648 | 647 |
response = client.post( |
... | ... | |
662 | 661 |
'url': [slapd.ldap_url], |
663 | 662 |
'basedn': 'o=ôrga', |
664 | 663 |
'use_tls': False, |
665 |
'groupstaff': [u'cn=group1,o=ôrga'],
|
|
664 |
'groupstaff': ['cn=group1,o=ôrga'], |
|
666 | 665 |
} |
667 | 666 |
] |
668 | 667 |
response = client.post( |
... | ... | |
687 | 686 |
'use_tls': False, |
688 | 687 |
'create_group': True, |
689 | 688 |
'group_mapping': [ |
690 |
[u'cn=group2,o=ôrga', ['Group2']],
|
|
689 |
['cn=group2,o=ôrga', ['Group2']], |
|
691 | 690 |
], |
692 | 691 |
'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))', |
693 | 692 |
'group_to_role_mapping': [ |
... | ... | |
772 | 771 |
'use_tls': False, |
773 | 772 |
'create_group': True, |
774 | 773 |
'group_mapping': [ |
775 |
[u'cn=group2,o=ôrga', ['Group2']],
|
|
774 |
['cn=group2,o=ôrga', ['Group2']], |
|
776 | 775 |
], |
777 | 776 |
'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))', |
778 | 777 |
'set_mandatory_roles': ['tech', 'admin'], |
... | ... | |
791 | 790 |
'use_tls': False, |
792 | 791 |
'create_group': True, |
793 | 792 |
'group_mapping': [ |
794 |
[u'cn=group2,o=ôrga', ['Group2']],
|
|
793 |
['cn=group2,o=ôrga', ['Group2']], |
|
795 | 794 |
], |
796 | 795 |
'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))', |
797 | 796 |
'set_mandatory_roles': ['tech', 'admin'], |
... | ... | |
814 | 813 |
'use_tls': False, |
815 | 814 |
'create_group': True, |
816 | 815 |
'group_mapping': [ |
817 |
[u'cn=group2,o=ôrga', ['Group2']],
|
|
816 |
['cn=group2,o=ôrga', ['Group2']], |
|
818 | 817 |
], |
819 | 818 |
'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))', |
820 | 819 |
'set_mandatory_roles': ['tech', 'admin'], |
... | ... | |
839 | 838 |
'use_tls': False, |
840 | 839 |
'create_group': True, |
841 | 840 |
'group_mapping': [ |
842 |
[u'cn=group2,o=ôrga', ['Group2']],
|
|
841 |
['cn=group2,o=ôrga', ['Group2']], |
|
843 | 842 |
], |
844 | 843 |
'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))', |
845 | 844 |
'set_mandatory_roles': ['tech'], |
... | ... | |
865 | 864 |
'use_tls': False, |
866 | 865 |
'create_group': True, |
867 | 866 |
'group_mapping': [ |
868 |
[u'cn=group2,o=ôrga', ['Group2']],
|
|
867 |
['cn=group2,o=ôrga', ['Group2']], |
|
869 | 868 |
], |
870 | 869 |
'group_filter': '(&(memberUid={uid})(objectClass=posixGroup))', |
871 | 870 |
'set_mandatory_roles': ['tech'], |
... | ... | |
1115 | 1114 |
'use_tls': False, |
1116 | 1115 |
} |
1117 | 1116 |
] |
1118 |
user = authenticate(username=u'etienne.michu', password=u'passé')
|
|
1117 |
user = authenticate(username='etienne.michu', password='passé')
|
|
1119 | 1118 |
assert user |
1120 |
assert user.check_password(u'passé')
|
|
1121 |
user.set_password(u'àbon')
|
|
1122 |
assert user.check_password(u'àbon')
|
|
1123 |
user2 = authenticate(username=u'etienne.michu', password=u'àbon')
|
|
1119 |
assert user.check_password('passé') |
|
1120 |
user.set_password('àbon') |
|
1121 |
assert user.check_password('àbon') |
|
1122 |
user2 = authenticate(username='etienne.michu', password='àbon')
|
|
1124 | 1123 |
assert user.pk == user2.pk |
1125 | 1124 | |
1126 | 1125 | |
... | ... | |
1255 | 1254 |
settings.LDAP_AUTH_SETTINGS = [ |
1256 | 1255 |
{ |
1257 | 1256 |
'url': [slapd_ppolicy.ldap_url], |
1258 |
'basedn': u'o=ôrga',
|
|
1259 |
'ppolicy_dn': u'cn=default,ou=ppolicies,o=ôrga',
|
|
1257 |
'basedn': 'o=ôrga', |
|
1258 |
'ppolicy_dn': 'cn=default,ou=ppolicies,o=ôrga', |
|
1260 | 1259 |
'use_tls': False, |
1261 | 1260 |
} |
1262 | 1261 |
] |
... | ... | |
1293 | 1292 | |
1294 | 1293 |
user = authenticate(username=USERNAME, password=UPASS) |
1295 | 1294 |
assert user.check_password(UPASS) |
1296 |
password = u'ogutOmyetew4'
|
|
1295 |
password = 'ogutOmyetew4' |
|
1297 | 1296 |
user.set_password(password) |
1298 | 1297 | |
1299 | 1298 |
time.sleep(pwdMaxAge * 3) |
... | ... | |
1504 | 1503 |
) |
1505 | 1504 | |
1506 | 1505 |
user = authenticate(username=USERNAME, password=UPASS) |
1507 |
assert user.set_password(u'ogutOmyetew4') is None
|
|
1506 |
assert user.set_password('ogutOmyetew4') is None |
|
1508 | 1507 |
assert 'STRONG_AUTH_REQUIRED' in caplog.text |
1509 | 1508 | |
1510 | 1509 | |
... | ... | |
1649 | 1648 |
assert user |
1650 | 1649 |
assert user.get_attributes(object(), {}) == { |
1651 | 1650 |
'dn': 'cn=étienne michu,o=\xf4rga', |
1652 |
'givenname': [u'Étienne'],
|
|
1653 |
'mail': [u'etienne.michu@example.net'],
|
|
1654 |
'sn': [u'Michu'],
|
|
1655 |
'uid': [u'etienne.michu'],
|
|
1651 |
'givenname': ['Étienne'], |
|
1652 |
'mail': ['etienne.michu@example.net'], |
|
1653 |
'sn': ['Michu'], |
|
1654 |
'uid': ['etienne.michu'], |
|
1656 | 1655 |
'carlicense': ['123445ABC'], |
1657 | 1656 |
} |
1658 | 1657 |
# simulate LDAP down |
1659 | 1658 |
slapd.stop() |
1660 | 1659 |
assert user.get_attributes(object(), {}) == { |
1661 | 1660 |
'dn': 'cn=étienne michu,o=\xf4rga', |
1662 |
'givenname': [u'\xc9tienne'],
|
|
1663 |
'mail': [u'etienne.michu@example.net'],
|
|
1664 |
'sn': [u'Michu'],
|
|
1665 |
'uid': [u'etienne.michu'],
|
|
1661 |
'givenname': ['\xc9tienne'], |
|
1662 |
'mail': ['etienne.michu@example.net'], |
|
1663 |
'sn': ['Michu'], |
|
1664 |
'uid': ['etienne.michu'], |
|
1666 | 1665 |
'carlicense': ['123445ABC'], |
1667 | 1666 |
} |
1668 | 1667 |
assert not user.check_password(UPASS) |
... | ... | |
1675 | 1674 |
conn.modify_s(DN, ldif) |
1676 | 1675 |
assert user.get_attributes(object(), {}) == { |
1677 | 1676 |
'dn': 'cn=étienne michu,o=\xf4rga', |
1678 |
'givenname': [u'\xc9tienne'],
|
|
1679 |
'mail': [u'etienne.michu@example.net'],
|
|
1680 |
'sn': [u'Micho'],
|
|
1681 |
'uid': [u'etienne.michu'],
|
|
1677 |
'givenname': ['\xc9tienne'], |
|
1678 |
'mail': ['etienne.michu@example.net'], |
|
1679 |
'sn': ['Micho'], |
|
1680 |
'uid': ['etienne.michu'], |
|
1682 | 1681 |
'carlicense': ['123445ABC'], |
1683 | 1682 |
} |
1684 | 1683 |
tests/test_login.py | ||
---|---|---|
203 | 203 |
assert not response.pyquery('.errorlist') |
204 | 204 |
assert response.pyquery.find('select#id_ou') |
205 | 205 |
assert len(response.pyquery.find('select#id_ou optgroup')) == 0 |
206 |
assert set([elt.text for elt in response.pyquery.find('select#id_ou option')]) == set( |
|
207 |
[u'Default organizational unit', 'OU1', 'OU2', '---------'] |
|
208 |
) |
|
206 |
assert {elt.text for elt in response.pyquery.find('select#id_ou option')} == { |
|
207 |
'Default organizational unit', |
|
208 |
'OU1', |
|
209 |
'OU2', |
|
210 |
'---------', |
|
211 |
} |
|
209 | 212 |
# Check selector is required |
210 | 213 |
response.form.set('username', simple_user.username) |
211 | 214 |
response.form.set('password', simple_user.username) |
... | ... | |
230 | 233 |
response = app.get('/login/') |
231 | 234 |
assert response.pyquery.find('select#id_ou') |
232 | 235 |
assert len(response.pyquery.find('select#id_ou optgroup')) == 2 |
233 |
assert set([elt.text for elt in response.pyquery.find('select#id_ou option')]) == set( |
|
234 |
[u'Default organizational unit', 'OU1', 'OU2', '---------'] |
|
235 |
) |
|
236 |
assert {elt.text for elt in response.pyquery.find('select#id_ou option')} == { |
|
237 |
'Default organizational unit', |
|
238 |
'OU1', |
|
239 |
'OU2', |
|
240 |
'---------', |
|
241 |
} |
|
236 | 242 |
assert response.pyquery.find('select#id_ou option[selected]')[0].text == 'Default organizational unit' |
237 | 243 | |
238 | 244 |
# Create a service |
tests/test_manager.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
... | ... | |
15 | 14 |
# You should have received a copy of the GNU Affero General Public License |
16 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 16 | |
18 |
from __future__ import unicode_literals |
|
19 | 17 | |
20 | 18 |
import json |
21 | 19 |
from urllib.parse import urlparse |
... | ... | |
370 | 368 |
# verify table shown |
371 | 369 |
q = response.pyquery.remove_namespaces() |
372 | 370 |
assert len(q('table tbody tr')) == 2 |
373 |
assert set([e.text for e in q('table tbody td.username')]) == {'admin', 'superuser'}
|
|
371 |
assert {e.text for e in q('table tbody td.username')} == {'admin', 'superuser'}
|
|
374 | 372 | |
375 | 373 |
# test user's role page |
376 | 374 |
response = app.get('/manage/users/%d/roles/' % admin.pk) |
... | ... | |
429 | 427 |
# verify table shown |
430 | 428 |
q = response.pyquery.remove_namespaces() |
431 | 429 |
assert len(q('table tbody tr')) == 3 |
432 |
assert set([e.text for e in q('table tbody td.username')]) == {'admin', 'superuser', 'admin.ou1'}
|
|
430 |
assert {e.text for e in q('table tbody td.username')} == {'admin', 'superuser', 'admin.ou1'}
|
|
433 | 431 | |
434 | 432 |
# test user's role page |
435 | 433 |
response = app.get('/manage/users/%d/roles/' % admin.pk) |
... | ... | |
483 | 481 |
q = response.pyquery.remove_namespaces() |
484 | 482 |
assert len(q('table tbody tr')) == 2 |
485 | 483 |
names = [elt.text for elt in q('table tbody td.name a')] |
486 |
assert set(names) == {u'simple role', 'role_ou1'}
|
|
484 |
assert set(names) == {'simple role', 'role_ou1'} |
|
487 | 485 | |
488 | 486 |
response.form.set('search-ou', 'all') |
489 | 487 |
response.form.set('search-internals', True) |
... | ... | |
531 | 529 |
q = response.pyquery.remove_namespaces() |
532 | 530 |
# only admin.ou1 is visible |
533 | 531 |
assert len(q('table tbody tr')) == 1 |
534 |
assert set([e.text for e in q('table tbody td.username')]) == {'admin.ou1'}
|
|
532 |
assert {e.text for e in q('table tbody td.username')} == {'admin.ou1'}
|
|
535 | 533 | |
536 | 534 |
# test user's role page |
537 | 535 |
response = app.get('/manage/users/%d/roles/' % admin.pk) |
... | ... | |
566 | 564 |
q = response.pyquery.remove_namespaces() |
567 | 565 |
assert len(q('table tbody tr')) == 1 |
568 | 566 |
names = [elt.text for elt in q('table tbody td.name a')] |
569 |
assert set(names) == {u'role_ou1'}
|
|
567 |
assert set(names) == {'role_ou1'} |
|
570 | 568 | |
571 | 569 |
response.form.set('search-internals', True) |
572 | 570 |
response = response.form.submit() |
... | ... | |
619 | 617 |
q = response.pyquery.remove_namespaces() |
620 | 618 |
assert len(q('table tbody tr')) == 1 |
621 | 619 |
names = [elt.text for elt in q('table tbody td.name a')] |
622 |
assert set(names) == {u'Auto Admin Role'}
|
|
620 |
assert set(names) == {'Auto Admin Role'} |
|
623 | 621 | |
624 | 622 |
response.form.set('search-internals', True) |
625 | 623 |
response = response.form.submit() |
626 | 624 |
q = response.pyquery.remove_namespaces() |
627 | 625 |
assert len(q('table tbody tr')) == 1 |
628 | 626 |
names = {elt.text for elt in q('table tbody td.name a')} |
629 |
assert set(names) == {u'Auto Admin Role'}
|
|
627 |
assert set(names) == {'Auto Admin Role'} |
|
630 | 628 | |
631 | 629 |
test_user_listing_auto_admin_role(user_with_auto_admin_role) |
632 | 630 | |
... | ... | |
775 | 773 |
def test_manager_ou(app, superuser_or_admin, ou1): |
776 | 774 |
manager_home_page = login(app, superuser_or_admin, reverse('a2-manager-homepage')) |
777 | 775 |
ou_homepage = manager_home_page.click(href='organizational-units') |
778 |
assert set([e.text for e in ou_homepage.pyquery('td.name')]) == set( |
|
779 |
['OU1', 'Default organizational unit'] |
|
780 |
) |
|
776 |
assert {e.text for e in ou_homepage.pyquery('td.name')} == {'OU1', 'Default organizational unit'} |
|
781 | 777 |
assert [x.text for x in ou_homepage.pyquery('td.slug')] == ['default', 'ou1'] |
782 | 778 | |
783 | 779 |
# add a new ou |
... | ... | |
786 | 782 |
add_ou_page.form.set('default', True) |
787 | 783 |
ou_homepage = add_ou_page.form.submit().follow() |
788 | 784 |
ou2 = OU.objects.get(name='ou2') |
789 |
assert set([e.text for e in ou_homepage.pyquery('td.name')]) == set( |
|
790 |
['OU1', 'Default organizational unit', 'ou2'] |
|
791 |
) |
|
785 |
assert {e.text for e in ou_homepage.pyquery('td.name')} == {'OU1', 'Default organizational unit', 'ou2'} |
|
792 | 786 |
assert len(ou_homepage.pyquery('tr[data-pk="%s"] td.default span.true' % ou2.pk)) == 1 |
793 | 787 |
assert len(ou_homepage.pyquery('tr[data-url="%s/"] td.default span.true' % ou2.pk)) == 1 |
794 | 788 | |
... | ... | |
801 | 795 |
ou1_detail_page = app.get(reverse('a2-manager-ou-detail', kwargs={'pk': ou1.pk})) |
802 | 796 |
ou1_delete_page = ou1_detail_page.click('Delete') |
803 | 797 |
ou_homepage = ou1_delete_page.form.submit().follow() |
804 |
assert set([e.text for e in ou_homepage.pyquery('td.name')]) == set( |
|
805 |
['Default organizational unit', 'ou2'] |
|
806 |
) |
|
798 |
assert {e.text for e in ou_homepage.pyquery('td.name')} == {'Default organizational unit', 'ou2'} |
|
807 | 799 | |
808 | 800 |
# remake old default ou the default one |
809 | 801 |
old_default = OU.objects.get(name__contains='Default') |
... | ... | |
816 | 808 |
assert old_default_detail_page.pyquery('input[name="default"][checked="checked"]') |
817 | 809 |
# check ou homepage has changed too |
818 | 810 |
ou_homepage = old_default_detail_page.click('Organizational unit') |
819 |
assert set([e.text for e in ou_homepage.pyquery('td.name')]) == set( |
|
820 |
['Default organizational unit', 'ou2'] |
|
821 |
) |
|
811 |
assert {e.text for e in ou_homepage.pyquery('td.name')} == {'Default organizational unit', 'ou2'} |
|
822 | 812 |
assert len(ou_homepage.pyquery('span.true')) == 1 |
823 | 813 |
assert len(ou_homepage.pyquery('tr[data-pk="%s"] td.default span.true' % ou2.pk)) == 0 |
824 | 814 |
assert len(ou_homepage.pyquery('tr[data-pk="%s"] td.default span.true' % old_default.pk)) == 1 |
... | ... | |
844 | 834 |
from authentic2.manager.forms import ChooseRoleForm |
845 | 835 | |
846 | 836 |
login(app, admin, '/manage/') |
847 |
cassis = OU.objects.create(name=u'Cassis')
|
|
848 |
la_bedoule = OU.objects.create(name=u'La Bédoule')
|
|
849 |
cuges = OU.objects.create(name=u'Cuges')
|
|
850 |
Role.objects.create(ou=cassis, name=u'Administrateur')
|
|
851 |
Role.objects.create(ou=la_bedoule, name=u'Administrateur')
|
|
852 |
Role.objects.create(ou=cuges, name=u'Administrateur')
|
|
837 |
cassis = OU.objects.create(name='Cassis') |
|
838 |
la_bedoule = OU.objects.create(name='La Bédoule') |
|
839 |
cuges = OU.objects.create(name='Cuges') |
|
840 |
Role.objects.create(ou=cassis, name='Administrateur') |
|
841 |
Role.objects.create(ou=la_bedoule, name='Administrateur') |
|
842 |
Role.objects.create(ou=cuges, name='Administrateur') |
|
853 | 843 | |
854 | 844 |
form = ChooseRoleForm(request=None) |
855 | 845 |
assert form.as_p() |
... | ... | |
869 | 859 |
from authentic2.manager.forms import RoleParentsForm |
870 | 860 | |
871 | 861 |
login(app, admin, '/manage/') |
872 |
Role.objects.create(name=u'admin 1')
|
|
873 |
Role.objects.create(name=u'user 1')
|
|
862 |
Role.objects.create(name='admin 1') |
|
863 |
Role.objects.create(name='user 1') |
|
874 | 864 | |
875 | 865 |
form = RoleParentsForm(request=None) |
876 | 866 |
assert form.as_p() |
... | ... | |
914 | 904 |
response = app.get('/manage/users/') |
915 | 905 |
q = response.pyquery.remove_namespaces() |
916 | 906 |
assert len(q('table tbody tr')) == 2 |
917 |
assert set([e.text for e in q('table tbody td.username')]) == {'admin', 'user'}
|
|
907 |
assert {e.text for e in q('table tbody td.username')} == {'admin', 'user'}
|
|
918 | 908 | |
919 | 909 |
# user can view administered roles |
920 | 910 |
response = app.get('/manage/roles/') |
... | ... | |
1086 | 1076 |
def get_choices(response): |
1087 | 1077 |
select2_json = request_select2(app, response) |
1088 | 1078 |
assert select2_json['more'] is False |
1089 |
return set(result['id'] for result in select2_json['results'])
|
|
1079 |
return {result['id'] for result in select2_json['results']}
|
|
1090 | 1080 | |
1091 | 1081 |
visible_role = Role.objects.create(name='visible_role', ou=simple_user.ou) |
1092 | 1082 |
Role.objects.create(name='invisible_role', ou=simple_user.ou) |
... | ... | |
1105 | 1095 | |
1106 | 1096 |
# all visible roles are shown |
1107 | 1097 |
response = app.get('/manage/roles/%s/add-child/' % simple_role.pk) |
1108 |
assert set([visible_role.pk, simple_role.pk]) == get_choices(response)
|
|
1098 |
assert {visible_role.pk, simple_role.pk} == get_choices(response)
|
|
1109 | 1099 | |
1110 | 1100 |
# all roles with manage_members permissions are shown |
1111 | 1101 |
response = app.get('/manage/roles/%s/add-parent/' % simple_role.pk) |
1112 |
assert set([simple_role.pk, admin_of_simple_role.pk]) == get_choices(response)
|
|
1102 |
assert {simple_role.pk, admin_of_simple_role.pk} == get_choices(response)
|
|
1113 | 1103 | |
1114 | 1104 |
response = app.get('/manage/roles/%s/add-parent/' % visible_role.pk) |
1115 |
assert set([simple_role.pk, admin_of_simple_role.pk]) == get_choices(response)
|
|
1105 |
assert {simple_role.pk, admin_of_simple_role.pk} == get_choices(response)
|
|
1116 | 1106 | |
1117 | 1107 | |
1118 | 1108 |
def test_manager_widgets_field_id_other_user(app, admin, simple_user, simple_role): |
... | ... | |
1124 | 1114 |
assert select2_json['more'] is False |
1125 | 1115 | |
1126 | 1116 |
# admin can see every roles |
1127 |
assert set([simple_role.pk, other_role.pk]) == set(result['id'] for result in select2_json['results'])
|
|
1117 |
assert {simple_role.pk, other_role.pk} == {result['id'] for result in select2_json['results']}
|
|
1128 | 1118 | |
1129 | 1119 |
login(app, simple_user) |
1130 | 1120 |
# same request from the page served for admin |
tests/test_manager_journal.py | ||
---|---|---|
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 | 17 |
import datetime |
18 |
from unittest import mock |
|
18 | 19 | |
19 |
import mock |
|
20 | 20 |
import pytest |
21 | 21 |
from django.contrib.sessions.models import Session |
22 | 22 |
from django.utils.timezone import make_aware |
tests/test_manager_user_import.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
... | ... | |
15 | 14 |
# You should have received a copy of the GNU Affero General Public License |
16 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 16 | |
18 |
from __future__ import unicode_literals |
|
19 | 17 | |
20 | 18 |
import io |
21 | 19 |
import operator |
tests/test_models.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
... | ... | |
15 | 14 |
# You should have received a copy of the GNU Affero General Public License |
16 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 16 | |
18 |
from __future__ import unicode_literals |
|
19 | 17 | |
20 | 18 |
import pytest |
21 | 19 |
tests/test_ou_manager.py | ||
---|---|---|
34 | 34 | |
35 | 35 |
assert list(export.keys()) == ['ous'] |
36 | 36 |
assert len(export['ous']) == 3 |
37 |
assert set([ou['slug'] for ou in export['ous']]) == set(['default', 'ou1', 'ou2'])
|
|
37 |
assert {ou['slug'] for ou in export['ous']} == {'default', 'ou1', 'ou2'}
|
|
38 | 38 | |
39 | 39 |
response.form.set('search-text', 'ou1') |
40 | 40 |
search_response = response.form.submit() |
tests/test_passwords.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import unicode_literals |
|
18 | 17 | |
19 | 18 |
import string |
20 | 19 | |
... | ... | |
23 | 22 | |
24 | 23 | |
25 | 24 |
def test_generate_password(): |
26 |
passwords = set(generate_password() for i in range(10))
|
|
25 |
passwords = {generate_password() for i in range(10)}
|
|
27 | 26 | |
28 | 27 |
char_classes = [string.digits, string.ascii_lowercase, string.ascii_uppercase, string.punctuation] |
29 | 28 |
assert len(passwords) == 10 |
tests/test_profile.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | ||
3 | 1 |
# authentic2 - versatile identity manager |
4 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
5 | 3 |
# |
... | ... | |
16 | 14 |
# You should have received a copy of the GNU Affero General Public License |
17 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | 16 | |
19 |
from __future__ import unicode_literals |
|
20 | 17 | |
21 | 18 |
import pytest |
22 | 19 |
from django.urls import reverse |
... | ... | |
163 | 160 |
) |
164 | 161 | |
165 | 162 |
def get_fields(resp): |
166 |
return set(
|
|
163 |
return {
|
|
167 | 164 |
key for key in resp.form.fields.keys() if key and key not in ['csrfmiddlewaretoken', 'cancel'] |
168 |
)
|
|
165 |
}
|
|
169 | 166 | |
170 | 167 |
resp = app.get(url, status=200) |
171 |
assert get_fields(resp) == set( |
|
172 |
['first_name', 'last_name', 'phone', 'mobile', 'city', 'zipcode', 'next_url'] |
|
173 |
) |
|
168 |
assert get_fields(resp) == {'first_name', 'last_name', 'phone', 'mobile', 'city', 'zipcode', 'next_url'} |
|
174 | 169 | |
175 | 170 |
resp = app.get(url + '?scope=contact', status=200) |
176 |
assert get_fields(resp) == set(['phone', 'mobile', 'next_url'])
|
|
171 |
assert get_fields(resp) == {'phone', 'mobile', 'next_url'}
|
|
177 | 172 | |
178 | 173 |
resp = app.get(url + '?scope=address', status=200) |
179 |
assert get_fields(resp) == set(['city', 'zipcode', 'next_url'])
|
|
174 |
assert get_fields(resp) == {'city', 'zipcode', 'next_url'}
|
|
180 | 175 | |
181 | 176 |
resp = app.get(url + '?scope=contact address', status=200) |
182 |
assert get_fields(resp) == set(['phone', 'mobile', 'city', 'zipcode', 'next_url'])
|
|
177 |
assert get_fields(resp) == {'phone', 'mobile', 'city', 'zipcode', 'next_url'}
|
|
183 | 178 | |
184 | 179 |
resp = app.get(reverse('profile_edit_with_scope', kwargs={'scope': 'contact'}), status=200) |
185 |
assert get_fields(resp) == set(['phone', 'mobile', 'next_url'])
|
|
180 |
assert get_fields(resp) == {'phone', 'mobile', 'next_url'}
|
|
186 | 181 | |
187 | 182 |
resp = app.get(reverse('profile_edit_with_scope', kwargs={'scope': 'address'}), status=200) |
188 |
assert get_fields(resp) == set(['city', 'zipcode', 'next_url'])
|
|
183 |
assert get_fields(resp) == {'city', 'zipcode', 'next_url'}
|
|
189 | 184 | |
190 | 185 | |
191 | 186 |
def test_account_edit_locked_title(app, simple_user): |
tests/test_registration.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
... | ... | |
330 | 329 |
# disable existing attributes |
331 | 330 |
models.Attribute.objects.update(disabled=True) |
332 | 331 | |
333 |
models.Attribute.objects.create(label=u'Prénom', name='prenom', required=True, kind='string')
|
|
332 |
models.Attribute.objects.create(label='Prénom', name='prenom', required=True, kind='string') |
|
334 | 333 |
models.Attribute.objects.create( |
335 |
label=u'Nom', name='nom', asked_on_registration=True, user_visible=True, kind='string'
|
|
334 |
label='Nom', name='nom', asked_on_registration=True, user_visible=True, kind='string' |
|
336 | 335 |
) |
337 | 336 |
models.Attribute.objects.create(label='Profession', name='profession', user_editable=True, kind='string') |
338 | 337 | |
... | ... | |
448 | 447 | |
449 | 448 |
response = app.get(activation_url, status=200) |
450 | 449 |
assert 'form' in response.context |
451 |
assert set(response.context['form'].fields.keys()) == set(['first_name', 'last_name'])
|
|
450 |
assert set(response.context['form'].fields.keys()) == {'first_name', 'last_name'}
|
|
452 | 451 | |
453 | 452 |
activation_url = utils.build_activation_url( |
454 | 453 |
rf.post('/accounts/register/'), |
tests/test_role_manager.py | ||
---|---|---|
36 | 36 | |
37 | 37 |
assert list(export.keys()) == ['roles'] |
38 | 38 |
assert len(export['roles']) == 2 |
39 |
assert set([role['slug'] for role in export['roles']]) == set(['role_ou1', 'role_ou2'])
|
|
39 |
assert {role['slug'] for role in export['roles']} == {'role_ou1', 'role_ou2'}
|
|
40 | 40 | |
41 | 41 |
export_response = response.click('CSV', href='/export/') |
42 | 42 |
reader = csv.reader( |
... | ... | |
46 | 46 | |
47 | 47 |
assert rows[0] == ['name', 'slug', 'members', 'ou'] |
48 | 48 |
assert len(rows) - 2 == 2 # csv header and last EOL |
49 |
assert set([row[1] for row in rows[1:3]]) == set(['role_ou1', 'role_ou2'])
|
|
50 |
assert set([row[3] for row in rows[1:3]]) == set(['OU1', 'OU2'])
|
|
49 |
assert {row[1] for row in rows[1:3]} == {'role_ou1', 'role_ou2'}
|
|
50 |
assert {row[3] for row in rows[1:3]} == {'OU1', 'OU2'}
|
|
51 | 51 | |
52 | 52 |
response.form.set('search-text', 'role_ou1') |
53 | 53 |
search_response = response.form.submit() |
tests/test_token.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from __future__ import unicode_literals |
|
18 | 17 | |
19 | 18 |
import pytest |
20 | 19 |
tests/test_user_manager.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
... | ... | |
15 | 14 |
# You should have received a copy of the GNU Affero General Public License |
16 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 16 | |
18 |
from __future__ import unicode_literals |
|
19 | 17 | |
20 | 18 |
import csv |
21 | 19 |
import datetime |
... | ... | |
44 | 42 | |
45 | 43 | |
46 | 44 |
def visible_users(response): |
47 |
return set(elt.text for elt in response.pyquery('td.username'))
|
|
45 |
return {elt.text for elt in response.pyquery('td.username')}
|
|
48 | 46 | |
49 | 47 | |
50 | 48 |
def test_create_user(app, superuser): |
... | ... | |
690 | 688 |
login(app, admin, '/manage/users/') |
691 | 689 | |
692 | 690 |
csv_lines = [ |
693 |
u"email key verified,first_name,last_name,more,title,bike,saintsday,birthdate,zip,phone",
|
|
694 |
u"elliot@universalpictures.com,Elliott,Thomas,petit,Mr,True,2019-7-20,1972-05-26,75014,1234",
|
|
695 |
u"et@universalpictures.com,ET,the Extra-Terrestrial,long,??,False,1/2/3/4,0002-2-22,42,home",
|
|
691 |
"email key verified,first_name,last_name,more,title,bike,saintsday,birthdate,zip,phone", |
|
692 |
"elliot@universalpictures.com,Elliott,Thomas,petit,Mr,True,2019-7-20,1972-05-26,75014,1234", |
|
693 |
"et@universalpictures.com,ET,the Extra-Terrestrial,long,??,False,1/2/3/4,0002-2-22,42,home", |
|
696 | 694 |
] |
697 | 695 |
response = import_csv('\n'.join(csv_lines), app) |
698 | 696 |
urls = re.findall('<a href="(/manage/users/import/[^/]+/[^/]+/)">', response.text) |
... | ... | |
713 | 711 |
assert elliot.attributes.values['zip'].content == '75014' |
714 | 712 |
assert elliot.attributes.values['phone'].content == '1234' |
715 | 713 | |
716 |
csv_lines[2] = u"et@universalpictures.com,ET,the Extra-Terrestrial,,,,,,42000,+888 5678"
|
|
714 |
csv_lines[2] = "et@universalpictures.com,ET,the Extra-Terrestrial,,,,,,42000,+888 5678" |
|
717 | 715 |
response = import_csv('\n'.join(csv_lines), app) |
718 | 716 |
assert '0 rows have errors' in response.text |
719 | 717 | |
... | ... | |
729 | 727 | |
730 | 728 | |
731 | 729 |
def test_detail_view(app, admin, simple_user): |
732 |
url = '/manage/users/{user.pk}/'.format(user=simple_user)
|
|
730 |
url = f'/manage/users/{simple_user.pk}/'
|
|
733 | 731 |
login(app, admin, url) |
734 | 732 | |
735 | 733 | |
736 | 734 |
def test_detail_view_user_deleted(app, admin, simple_user): |
737 |
url = '/manage/users/{user.pk}/'.format(user=simple_user)
|
|
735 |
url = f'/manage/users/{simple_user.pk}/'
|
|
738 | 736 |
login(app, admin, url) |
739 | 737 |
simple_user.delete() |
740 | 738 |
app.get(url, status=404) |
... | ... | |
902 | 900 | |
903 | 901 | |
904 | 902 |
def test_ou_hide_username(admin, app, db): |
905 |
some_ou = OU.objects.create(name=u'Some Ou', show_username=False)
|
|
903 |
some_ou = OU.objects.create(name='Some Ou', show_username=False) |
|
906 | 904 | |
907 | 905 |
login(app, admin, '/manage/') |
908 | 906 |
url = '/manage/users/%s/add/' % some_ou.pk |
tests/test_validators.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 | 1 |
# authentic2 - versatile identity manager |
3 | 2 |
# Copyright (C) 2010-2019 Entr'ouvert |
4 | 3 |
# |
... | ... | |
15 | 14 |
# You should have received a copy of the GNU Affero General Public License |
16 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 16 | |
18 |
from __future__ import unicode_literals |
|
19 | 17 | |
20 | 18 |
import smtplib |
19 |
from unittest import mock |
|
21 | 20 | |
22 |
import mock |
|
23 | 21 |
import pytest |
24 | 22 |
from django.core.exceptions import ValidationError |
25 | 23 |
tests_rbac/test_rbac.py | ||
---|---|---|
127 | 127 |
Permission = utils.get_permission_model() |
128 | 128 |
User = get_user_model() |
129 | 129 |
OU = utils.get_ou_model() |
130 |
ou1 = OU.objects.create(name=u'ou1', slug=u'ou1')
|
|
131 |
ou2 = OU.objects.create(name=u'ou2', slug=u'ou2')
|
|
130 |
ou1 = OU.objects.create(name='ou1', slug='ou1')
|
|
131 |
ou2 = OU.objects.create(name='ou2', slug='ou2')
|
|
132 | 132 |
user1 = User.objects.create(username='john.doe') |
133 | 133 |
Role = utils.get_role_model() |
134 | 134 |
ct_ct = ContentType.objects.get_for_model(ContentType) |
... | ... | |
154 | 154 |
rbac_backend = backends.DjangoRBACBackend() |
155 | 155 |
ctx = CaptureQueriesContext(connection) |
156 | 156 |
with ctx: |
157 |
assert rbac_backend.get_all_permissions(user1) == set( |
|
158 |
['django_rbac.change_role', 'django_rbac.search_role', 'django_rbac.view_role'] |
|
159 |
) |
|
160 |
assert rbac_backend.get_all_permissions(user1, obj=role1) == set( |
|
161 |
[ |
|
162 |
'django_rbac.delete_role', |
|
163 |
'django_rbac.change_role', |
|
164 |
'django_rbac.search_role', |
|
165 |
'django_rbac.view_role', |
|
166 |
] |
|
167 |
) |
|
168 |
assert rbac_backend.get_all_permissions(user1, obj=role2) == set( |
|
169 |
[ |
|
170 |
'django_rbac.change_role', |
|
171 |
'django_rbac.view_role', |
|
172 |
'django_rbac.search_role', |
|
173 |
'django_rbac.add_role', |
|
174 |
] |
|
175 |
) |
|
157 |
assert rbac_backend.get_all_permissions(user1) == { |
|
158 |
'django_rbac.change_role', |
|
159 |
'django_rbac.search_role', |
|
160 |
'django_rbac.view_role', |
|
161 |
} |
|
162 |
assert rbac_backend.get_all_permissions(user1, obj=role1) == { |
|
163 |
'django_rbac.delete_role', |
|
164 |
'django_rbac.change_role', |
|
165 |
'django_rbac.search_role', |
|
166 |
'django_rbac.view_role', |
|
167 |
} |
|
168 |
assert rbac_backend.get_all_permissions(user1, obj=role2) == { |
|
169 |
'django_rbac.change_role', |
|
170 |
'django_rbac.view_role', |
|
171 |
'django_rbac.search_role', |
|
172 |
'django_rbac.add_role', |
|
173 |
} |
|
176 | 174 |
assert not rbac_backend.has_perm(user1, 'django_rbac.delete_role', obj=role2) |
177 | 175 |
assert rbac_backend.has_perm(user1, 'django_rbac.delete_role', obj=role1) |
178 | 176 |
assert rbac_backend.has_perms( |
... | ... | |
181 | 179 |
assert rbac_backend.has_module_perms(user1, 'django_rbac') |
182 | 180 |
assert not rbac_backend.has_module_perms(user1, 'contenttypes') |
183 | 181 |
assert len(ctx.captured_queries) == 1 |
184 |
assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.add_role', Role.objects.all())) == set([role2]) |
|
185 |
assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.delete_role', Role.objects.all())) == set( |
|
186 |
[role1] |
|
187 |
) |
|
182 |
assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.add_role', Role.objects.all())) == {role2} |
|
183 |
assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.delete_role', Role.objects.all())) == {role1} |
|
188 | 184 |
assert set( |
189 | 185 |
rbac_backend.filter_by_perm( |
190 | 186 |
user1, ['django_rbac.delete_role', 'django_rbac.add_role'], Role.objects.all() |
191 | 187 |
) |
192 |
) == set([role1, role2]) |
|
193 |
assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.view_role', Role.objects.all())) == set( |
|
194 |
[role1, role2] |
|
195 |
) |
|
196 |
assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.change_role', Role.objects.all())) == set( |
|
197 |
[role1, role2] |
|
198 |
) |
|
188 |
) == {role1, role2} |
|
189 |
assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.view_role', Role.objects.all())) == { |
|
190 |
role1, |
|
191 |
role2, |
|
192 |
} |
|
193 |
assert set(rbac_backend.filter_by_perm(user1, 'django_rbac.change_role', Role.objects.all())) == { |
|
194 |
role1, |
|
195 |
role2, |
|
196 |
} |
|
199 | 197 | |
200 | 198 |
# Test admin op as a generalization of other ops |
201 | 199 |
user2 = User.objects.create(username='donald.knuth') |
... | ... | |
203 | 201 |
role3.members.add(user2) |
204 | 202 |
perm5 = Permission.objects.create(operation=admin_op, target_ct=ct_ct, target_id=role_ct.pk) |
205 | 203 |
role3.permissions.add(perm5) |
206 |
assert rbac_backend.get_all_permissions(user2) == set( |
|
207 |
[ |
|
208 |
'django_rbac.add_role', |
|
209 |
'django_rbac.change_role', |
|
210 |
'django_rbac.search_role', |
|
211 |
'django_rbac.admin_role', |
|
212 |
'django_rbac.view_role', |
|
213 |
'django_rbac.delete_role', |
|
214 |
] |
|
215 |
) |
|
204 |
assert rbac_backend.get_all_permissions(user2) == { |
|
205 |
'django_rbac.add_role', |
|
206 |
'django_rbac.change_role', |
|
207 |
'django_rbac.search_role', |
|
208 |
'django_rbac.admin_role', |
|
209 |
'django_rbac.view_role', |
|
210 |
'django_rbac.delete_role', |
|
211 |
} |
|
216 | 212 | |
217 | 213 |
# test ous_with_perm |
218 |
assert set(rbac_backend.ous_with_perm(user1, 'django_rbac.add_role')) == set([ou1])
|
|
219 |
assert set(rbac_backend.ous_with_perm(user1, 'django_rbac.view_role')) == set([ou1, ou2])
|
|
220 |
assert set(rbac_backend.ous_with_perm(user1, 'django_rbac.delete_role')) == set([])
|
|
214 |
assert set(rbac_backend.ous_with_perm(user1, 'django_rbac.add_role')) == {ou1}
|
|
215 |
assert set(rbac_backend.ous_with_perm(user1, 'django_rbac.view_role')) == {ou1, ou2}
|
|
216 |
assert set(rbac_backend.ous_with_perm(user1, 'django_rbac.delete_role')) == set() |
|
221 | 217 | |
222 | 218 | |
223 | 219 |
def test_all_members(db): |
224 |
- |