0001-base-grant-endpoint-permissions-using-roles-38365.patch
passerelle/base/forms.py | ||
---|---|---|
1 | 1 |
from django import forms |
2 | 2 | |
3 |
from .models import ApiUser, AccessRight, AvailabilityParameters |
|
3 |
from .models import ApiUser, AccessRight, RoleAccessRight, AvailabilityParameters
|
|
4 | 4 | |
5 | 5 | |
6 | 6 |
class ApiUserForm(forms.ModelForm): |
... | ... | |
9 | 9 |
exclude = [] |
10 | 10 | |
11 | 11 | |
12 |
class AccessRightForm(forms.ModelForm): |
|
12 |
class BaseAccessRightForm(forms.ModelForm):
|
|
13 | 13 |
class Meta: |
14 |
model = AccessRight |
|
15 |
exclude = [] |
|
14 |
abstract = True |
|
16 | 15 |
widgets = { |
17 | 16 |
'codename': forms.HiddenInput(), |
18 | 17 |
'resource_type': forms.HiddenInput(), |
... | ... | |
20 | 19 |
} |
21 | 20 | |
22 | 21 | |
22 |
class AccessRightForm(BaseAccessRightForm): |
|
23 |
class Meta(BaseAccessRightForm.Meta): |
|
24 |
model = AccessRight |
|
25 |
fields = ['apiuser', 'codename', 'resource_type', 'resource_pk'] |
|
26 | ||
27 | ||
28 |
class RoleAccessRightForm(BaseAccessRightForm): |
|
29 |
class Meta(BaseAccessRightForm.Meta): |
|
30 |
model = RoleAccessRight |
|
31 |
fields = ['role', 'codename', 'resource_type', 'resource_pk'] |
|
32 | ||
33 | ||
23 | 34 |
class AvailabilityParametersForm(forms.ModelForm): |
24 | 35 |
class Meta: |
25 | 36 |
model = AvailabilityParameters |
passerelle/base/migrations/0017_auto_20191211_1509.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
# Generated by Django 1.11.18 on 2019-12-11 14:09 |
|
3 |
from __future__ import unicode_literals |
|
4 | ||
5 |
from django.db import migrations, models |
|
6 |
import django.db.models.deletion |
|
7 | ||
8 | ||
9 |
class Migration(migrations.Migration): |
|
10 | ||
11 |
dependencies = [ |
|
12 |
('contenttypes', '0002_remove_content_type_name'), |
|
13 |
('auth', '0008_alter_user_username_max_length'), |
|
14 |
('base', '0016_auto_20191002_1443'), |
|
15 |
] |
|
16 | ||
17 |
operations = [ |
|
18 |
migrations.CreateModel( |
|
19 |
name='RoleAccessRight', |
|
20 |
fields=[ |
|
21 |
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
22 |
('codename', models.CharField(max_length=100, verbose_name=b'codename')), |
|
23 |
('resource_pk', models.PositiveIntegerField()), |
|
24 |
('resource_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')), |
|
25 |
('role', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group', verbose_name='Role')), |
|
26 |
], |
|
27 |
options={ |
|
28 |
'permissions': (('view_accessright', 'Can view access right'),), |
|
29 |
}, |
|
30 |
), |
|
31 |
migrations.AlterUniqueTogether( |
|
32 |
name='roleaccessright', |
|
33 |
unique_together=set([('codename', 'resource_type', 'resource_pk', 'role')]), |
|
34 |
), |
|
35 |
] |
passerelle/base/models.py | ||
---|---|---|
12 | 12 | |
13 | 13 |
from django.apps import apps |
14 | 14 |
from django.conf import settings |
15 |
from django.contrib.auth.models import Group |
|
15 | 16 |
from django.core.exceptions import ValidationError, ObjectDoesNotExist, PermissionDenied |
16 | 17 |
from django.core.urlresolvers import reverse |
17 | 18 |
from django.db import connection, models, transaction |
... | ... | |
565 | 566 |
exc_info=exc_info) |
566 | 567 | |
567 | 568 | |
568 |
class AccessRight(models.Model): |
|
569 |
class BaseAccessRight(models.Model):
|
|
569 | 570 |
codename = models.CharField(max_length=100, verbose_name='codename') |
570 | 571 |
resource_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) |
571 | 572 |
resource_pk = models.PositiveIntegerField() |
572 | 573 |
resource = fields.GenericForeignKey('resource_type', 'resource_pk') |
573 |
apiuser = models.ForeignKey(ApiUser, verbose_name=_('API User'), on_delete=models.CASCADE) |
|
574 | 574 | |
575 | 575 |
class Meta: |
576 |
abstract = True |
|
576 | 577 |
permissions = ( |
577 | 578 |
('view_accessright', 'Can view access right'), |
578 | 579 |
) |
580 | ||
581 | ||
582 |
class AccessRight(BaseAccessRight): |
|
583 |
apiuser = models.ForeignKey(ApiUser, verbose_name=_('API User'), on_delete=models.CASCADE) |
|
584 | ||
585 |
class Meta(BaseAccessRight.Meta): |
|
579 | 586 |
unique_together = ( |
580 | 587 |
('codename', 'resource_type', 'resource_pk', 'apiuser'), |
581 | 588 |
) |
582 | 589 | |
583 | 590 |
def __unicode__(self): |
584 |
return '%s (on %s <%s>) (for %s)' % (self.codename, self.resource_type, self.resource_pk, self.apiuser) |
|
591 |
return '%s (on %s <%s>) (for %s)' % (self.codename, self.resource_type, |
|
592 |
self.resource_pk, self.apiuser) |
|
593 | ||
594 | ||
595 |
class RoleAccessRight(BaseAccessRight): |
|
596 |
role = models.ForeignKey(Group, verbose_name=_('Role'), on_delete=models.CASCADE) |
|
597 | ||
598 |
class Meta(BaseAccessRight.Meta): |
|
599 |
unique_together = ( |
|
600 |
('codename', 'resource_type', 'resource_pk', 'role'), |
|
601 |
) |
|
602 | ||
603 |
def __unicode__(self): |
|
604 |
return '%s (on %s <%s>) (for role %s)' % (self.codename, self.resource_type, |
|
605 |
self.resource_pk, self.role.name) |
|
585 | 606 | |
586 | 607 | |
587 | 608 |
class LoggingParameters(models.Model): |
passerelle/base/templatetags/passerelle.py | ||
---|---|---|
29 | 29 |
from django.template.defaultfilters import stringfilter |
30 | 30 | |
31 | 31 |
from passerelle.utils import get_trusted_services |
32 |
from ..models import AccessRight, ResourceLog |
|
32 |
from ..models import AccessRight, RoleAccessRight, ResourceLog
|
|
33 | 33 | |
34 | 34 |
register = template.Library() |
35 | 35 | |
... | ... | |
38 | 38 |
def access_rights_table(context, resource, permission): |
39 | 39 |
resource_type = ContentType.objects.get_for_model(resource) |
40 | 40 |
rights = AccessRight.objects.filter(resource_type=resource_type, resource_pk=resource.id, codename=permission) |
41 |
role_rights = RoleAccessRight.objects.filter(resource_type=resource_type, resource_pk=resource.id, |
|
42 |
codename=permission) |
|
41 | 43 |
context['permission'] = permission |
42 | 44 |
context['access_rights_list'] = rights |
45 |
context['role_access_rights_list'] = role_rights |
|
43 | 46 |
context['resource_type'] = resource_type.id |
44 | 47 |
context['resource_pk'] = resource.id |
45 | 48 |
context['trusted_services'] = get_trusted_services() |
passerelle/base/urls.py | ||
---|---|---|
2 | 2 | |
3 | 3 |
from .views import ApiUserCreateView, ApiUserUpdateView, ApiUserDeleteView, \ |
4 | 4 |
ApiUserListView, AccessRightDeleteView, AccessRightCreateView, \ |
5 |
LoggingParametersUpdateView, ManageAvailabilityView |
|
5 |
LoggingParametersUpdateView, ManageAvailabilityView, \ |
|
6 |
RoleAccessRightDeleteView, RoleAccessRightCreateView |
|
6 | 7 | |
7 | 8 |
access_urlpatterns = [ |
8 | 9 |
url(r'^$', ApiUserListView.as_view(), name='apiuser-list'), |
... | ... | |
14 | 15 |
name='access-right-remove'), |
15 | 16 |
url(r'^accessright/add/(?P<resource_type>[\w,-]+)/(?P<resource_pk>[\w,-]+)/(?P<codename>[\w,-]+)/', |
16 | 17 |
AccessRightCreateView.as_view(), name='access-right-add'), |
18 |
url(r'^(?P<pk>[\w,-]+)/roleremove$', RoleAccessRightDeleteView.as_view(), |
|
19 |
name='role-access-right-remove'), |
|
20 |
url(r'^roleaccessright/add/(?P<resource_type>[\w,-]+)/(?P<resource_pk>[\w,-]+)/(?P<codename>[\w,-]+)/', |
|
21 |
RoleAccessRightCreateView.as_view(), name='role-access-right-add'), |
|
17 | 22 |
url(r'logging/parameters/(?P<resource_type>[\w,-]+)/(?P<resource_pk>[\w,-]+)/$', |
18 | 23 |
LoggingParametersUpdateView.as_view(), name='logging-parameters'), |
19 | 24 |
url(r'manage/availability/(?P<resource_type>[\w,-]+)/(?P<resource_pk>[\w,-]+)/$', |
passerelle/base/views.py | ||
---|---|---|
30 | 30 |
from django.utils.timezone import make_aware |
31 | 31 |
from django.utils.translation import ugettext_lazy as _ |
32 | 32 | |
33 |
from .models import ApiUser, AccessRight, LoggingParameters, ResourceStatus, Job |
|
34 |
from .forms import ApiUserForm, AccessRightForm, AvailabilityParametersForm |
|
33 |
from .models import ApiUser, AccessRight, RoleAccessRight, LoggingParameters, ResourceStatus, Job
|
|
34 |
from .forms import ApiUserForm, AccessRightForm, RoleAccessRightForm, AvailabilityParametersForm
|
|
35 | 35 |
from ..views import GenericConnectorMixin |
36 | 36 |
from ..utils import get_trusted_services |
37 | 37 | |
... | ... | |
97 | 97 |
return context |
98 | 98 | |
99 | 99 | |
100 |
class AccessRightDeleteView(DeleteView): |
|
101 |
model = AccessRight |
|
100 |
class BaseAccessRightDeleteView(DeleteView): |
|
102 | 101 |
template_name = 'passerelle/manage/accessright_confirm_delete.html' |
103 | 102 | |
104 | 103 |
def get_object(self): |
105 |
object = super(AccessRightDeleteView, self).get_object() |
|
104 |
object = super(BaseAccessRightDeleteView, self).get_object()
|
|
106 | 105 |
self.resource = object.resource |
107 | 106 |
return object |
108 | 107 | |
... | ... | |
110 | 109 |
return self.resource.get_absolute_url() |
111 | 110 | |
112 | 111 | |
113 |
class AccessRightCreateView(CreateView):
|
|
112 |
class AccessRightDeleteView(BaseAccessRightDeleteView):
|
|
114 | 113 |
model = AccessRight |
115 |
form_class = AccessRightForm |
|
114 | ||
115 | ||
116 |
class RoleAccessRightDeleteView(BaseAccessRightDeleteView): |
|
117 |
model = RoleAccessRight |
|
118 | ||
119 | ||
120 |
class BaseAccessRightCreateView(CreateView): |
|
116 | 121 |
template_name = 'passerelle/manage/accessright_form.html' |
117 | 122 | |
118 | 123 |
def get_initial(self): |
... | ... | |
126 | 131 |
return self.object.resource.get_absolute_url() |
127 | 132 | |
128 | 133 | |
134 |
class AccessRightCreateView(BaseAccessRightCreateView): |
|
135 |
model = AccessRight |
|
136 |
form_class = AccessRightForm |
|
137 | ||
138 | ||
139 |
class RoleAccessRightCreateView(BaseAccessRightCreateView): |
|
140 |
model = RoleAccessRight |
|
141 |
form_class = RoleAccessRightForm |
|
142 | ||
143 | ||
129 | 144 |
class LoggingParametersUpdateView(FormView): |
130 | 145 |
template_name = 'passerelle/manage/logging_parameters_form.html' |
131 | 146 |
passerelle/templates/passerelle/includes/access-rights-table.html | ||
---|---|---|
23 | 23 |
{% endif %} |
24 | 24 |
</tr> |
25 | 25 |
{% endfor %} |
26 |
{% for object in role_access_rights_list %} |
|
27 |
<tr> |
|
28 |
<td>{{ object.role.name }}</td> |
|
29 |
<td> - </td> |
|
30 |
<td> - </td> |
|
31 |
{% if perms.base.delete_accessright %} |
|
32 |
<td><a rel="popup" class="icon-remove-sign" href="{% url 'role-access-right-remove' pk=object.id %}"></a></td> |
|
33 |
{% endif %} |
|
34 |
</tr> |
|
35 |
{% endfor %} |
|
26 | 36 |
{% for trusted_service in trusted_services %} |
27 | 37 |
<tr> |
28 | 38 |
<td>{{ trusted_service.title }} ({{ trusted_service.verif_orig }})</td> |
... | ... | |
37 | 47 |
{% if perms.base.add_accessright %} |
38 | 48 |
<p> |
39 | 49 |
<a rel="popup" class="icon-plus button" href="{% url 'access-right-add' resource_type=resource_type resource_pk=resource_pk codename=permission %}">{% trans 'Add' %}</a> |
50 |
<a rel="popup" class="icon-plus button" href="{% url 'role-access-right-add' resource_type=resource_type resource_pk=resource_pk codename=permission %}">{% trans 'Add role' %}</a> |
|
40 | 51 |
</p> |
41 | 52 |
{% endif %} |
passerelle/utils/__init__.py | ||
---|---|---|
121 | 121 |
return False |
122 | 122 | |
123 | 123 | |
124 |
def has_perm(user, obj, resource_type, perm): |
|
125 |
from passerelle.base.models import RoleAccessRight |
|
126 | ||
127 |
if user.is_anonymous: |
|
128 |
return False |
|
129 |
rights = RoleAccessRight.objects.filter(resource_type=resource_type, |
|
130 |
resource_pk=obj.id, codename=perm) |
|
131 |
role_ids = [x.role.id for x in rights] |
|
132 |
return user.groups.filter(id__in=role_ids).exists() |
|
133 | ||
134 | ||
124 | 135 |
def is_authorized(request, obj, perm): |
125 | 136 |
from passerelle.base.models import AccessRight |
126 | 137 | |
127 | 138 |
if is_trusted(request): |
128 | 139 |
return True |
129 | 140 |
resource_type = ContentType.objects.get_for_model(obj) |
141 |
if not request.user.is_anonymous and has_perm(request.user, obj, resource_type, perm): |
|
142 |
return True |
|
130 | 143 |
rights = AccessRight.objects.filter(resource_type=resource_type, resource_pk=obj.id, codename=perm) |
131 | 144 |
users = [x.apiuser for x in rights] |
132 | 145 |
return set(users).intersection(get_request_users(request)) |
133 |
- |