0002-manager-prevent-changing-ldap-sychronised-role-affec.patch
src/authentic2/manager/tables.py | ||
---|---|---|
122 | 122 |
'indeterminate{%% endif %%}"' |
123 | 123 |
' name="role-{{ record.pk }}" type="checkbox" {%% if record.member %%}checked{%% endif %%} ' |
124 | 124 |
'{%% if not record.has_perm %%}disabled ' |
125 |
'title="{%% trans "%s" %%}"{%% endif %%}/>' % ugettext_noop('You are not authorized to manage this role'), |
|
125 |
'title="{%% trans "%s" %%}"{%% endif %%} ' |
|
126 |
'{%% if record.from_ldap %%}disabled ' |
|
127 |
'title="{%% trans "%s" %%}"{%% endif %%}/>' % (ugettext_noop('You are not authorized to manage this role'), ugettext_noop('This role is synchronised from LDAP, changing members is not allowed.')), |
|
126 | 128 |
verbose_name=_('Member'), |
127 | 129 |
order_by=('member', 'via', 'name')) |
128 | 130 |
src/authentic2/manager/templates/authentic2/manager/user_roles_table.html | ||
---|---|---|
7 | 7 |
<th></th> |
8 | 8 |
{% endblock %} |
9 | 9 |
{% block table.tbody.last.column %} |
10 |
<td>{% if table.context.view.can_change and row.record.member %}<a class="icon-remove-sign js-remove-object" data-confirm="{% blocktrans with name=row.record.name username=table.context.object.get_full_name %}Do you really want to remove role "{{ name }}" from user "{{ username }}" ?{% endblocktrans %}" href="#" data-pk-arg="role"></a>{% endif %}</td> |
|
10 |
<td> |
|
11 |
{% if table.context.view.can_change and row.record.member %} |
|
12 |
<a class="icon-remove-sign {% if row.record.from_ldap %} disabled {% else %} js-remove-object {% endif %}" data-confirm="{% blocktrans with name=row.record.name username=table.context.object.get_full_name %}Do you really want to remove role "{{ name }}" from user "{{ username }}" ?{% endblocktrans %}" href="#" data-pk-arg="role" title="{% if row.record.from_ldap %}{% trans "This role is synchronised from LDAP, changing members is not allowed." %}{% endif %}"></a> |
|
13 |
{% endif %} |
|
14 |
</td> |
|
11 | 15 |
{% endblock %} |
12 | 16 |
{% endif %} |
src/authentic2/manager/user_views.py | ||
---|---|---|
19 | 19 |
import collections |
20 | 20 |
import operator |
21 | 21 | |
22 |
from django.conf import settings |
|
22 | 23 |
from django.db import models |
23 | 24 |
from django.utils.translation import ugettext_lazy as _, ugettext |
24 | 25 |
from django.utils.html import format_html |
... | ... | |
557 | 558 |
manageable_ids = map(str, qs2.values_list('pk', flat=True)) |
558 | 559 |
qs = qs.extra(select={'has_perm': 'a2_rbac_role.id in (%s)' % ', '.join(manageable_ids)}) |
559 | 560 |
qs = qs.exclude(slug__startswith='_a2-managers-of-role') |
560 |
return qs |
|
561 | 561 |
else: |
562 |
return self.object.roles_and_parents() |
|
562 |
qs = self.object.roles_and_parents() |
|
563 |
qs = self.flag_ldap_roles(qs) |
|
564 |
return qs |
|
565 | ||
566 |
def flag_ldap_roles(self, qs): |
|
567 |
mappings = getattr(settings, 'LDAP_AUTH_SETTINGS', [{}])[0].get('group_to_role_mapping', []) |
|
568 |
if mappings: |
|
569 |
role_names = [role for mapping in mappings for role in mapping[1]] |
|
570 |
roles = qs.filter(name__in=role_names) |
|
571 |
role_ids = map(str, roles.values_list('pk', flat=True)) |
|
572 |
qs = qs.extra(select={'from_ldap': 'a2_rbac_role.id in (%s)' % ', '.join(role_ids)}) |
|
573 |
return qs |
|
563 | 574 | |
564 | 575 |
def get_table_data(self): |
565 | 576 |
qs = super(UserRolesView, self).get_table_data() |
src/authentic2/manager/views.py | ||
---|---|---|
17 | 17 |
import json |
18 | 18 |
import inspect |
19 | 19 | |
20 |
from django.conf import settings |
|
21 |
from django.contrib import messages |
|
20 | 22 |
from django.core.exceptions import PermissionDenied |
21 | 23 |
from django.db import transaction |
22 | 24 |
from django.views.generic.base import ContextMixin |
... | ... | |
38 | 40 | |
39 | 41 |
from gadjo.templatetags.gadjo import xstatic |
40 | 42 | |
41 |
from django_rbac.utils import get_ou_model |
|
43 |
from django_rbac.utils import get_ou_model, get_role_model
|
|
42 | 44 | |
43 | 45 |
from authentic2.data_transfer import export_site, import_site, DataImportError, ImportContext |
44 | 46 |
from authentic2.forms.profile import modelform_factory |
... | ... | |
120 | 122 |
perm = '%s.%s_%s' % (app_label, permission, model_name) |
121 | 123 |
setattr(self, 'can_' + permission, |
122 | 124 |
request.user.has_perm(perm, self.object)) |
125 |
if self.can_manage_members: |
|
126 |
self.check_for_ldap_sync() |
|
123 | 127 |
if self.permissions \ |
124 | 128 |
and not request.user.has_perms( |
125 | 129 |
self.permissions, self.object): |
... | ... | |
134 | 138 |
if not self.permissions_global and not request.user.has_perm_any(self.permissions): |
135 | 139 |
raise PermissionDenied |
136 | 140 | |
141 |
def check_for_ldap_sync(self): |
|
142 |
if not isinstance(self.object, get_role_model()): |
|
143 |
return |
|
144 |
mappings = getattr(settings, 'LDAP_AUTH_SETTINGS', [{}])[0].get('group_to_role_mapping', []) |
|
145 |
if mappings and any(role for mapping in mappings for role in mapping[1] |
|
146 |
if role == self.object.name): |
|
147 |
messages.info(self.request, |
|
148 |
'This role is synchronised from LDAP, changing members is not allowed.') |
|
149 |
self.can_manage_members = False |
|
150 | ||
151 | ||
137 | 152 |
def dispatch(self, request, *args, **kwargs): |
138 | 153 |
response = self.authorize(request, *args, **kwargs) |
139 | 154 |
if response is not None: |
tests/test_ldap.py | ||
---|---|---|
345 | 345 |
assert response.context['user'].roles.count() == 1 |
346 | 346 | |
347 | 347 | |
348 |
def test_group_to_role_mapping_modify_disabled(slapd, settings, db, app, admin, simple_user): |
|
349 |
from authentic2.a2_rbac.models import Role |
|
350 | ||
351 |
role = Role.objects.get_or_create(name='Role2', ou=simple_user.ou)[0] |
|
352 |
simple_user.roles.add(role) |
|
353 |
settings.LDAP_AUTH_SETTINGS = [{ |
|
354 |
'url': [slapd.ldap_url], |
|
355 |
'basedn': u'o=ôrga', |
|
356 |
'use_tls': False, |
|
357 |
'group_to_role_mapping': [ |
|
358 |
['cn=group2,o=ôrga', ['Role2']], |
|
359 |
], |
|
360 |
}] |
|
361 |
utils.login(app, admin, '/manage/') |
|
362 | ||
363 |
response = app.get('/manage/users/%s/roles/?search-ou=all' % simple_user.pk) |
|
364 |
q = response.pyquery.remove_namespaces() |
|
365 |
assert q('table tbody td.name').text() == 'Role2' |
|
366 |
assert q('table tbody td .disabled') |
|
367 | ||
368 |
response = app.get('/manage/users/%s/roles/?search-ou=%s' % (simple_user.pk, simple_user.ou.pk)) |
|
369 |
q = response.pyquery.remove_namespaces() |
|
370 |
assert q('table tbody td.name').text() == 'Role2' |
|
371 |
assert q('table tbody td.member input').attr('disabled') |
|
372 | ||
373 |
response = app.get('/manage/roles/%s/' % (role.pk)) |
|
374 |
q = response.pyquery.remove_namespaces() |
|
375 |
assert not q('form.manager-m2m-add-form') |
|
376 |
assert q('div.role-inheritance .role-add.disabled') |
|
377 |
assert not q('table tbody td a.icon-remove-sign js-remove-object') |
|
378 | ||
379 | ||
348 | 380 |
def test_group_su(slapd, settings, client, db): |
349 | 381 |
from django.contrib.auth.models import Group |
350 | 382 | |
351 |
- |