Commit 90869b05 authored by Rémi Duraffort's avatar Rémi Duraffort
Browse files

Merge branch 'rest-api-permission' into 'master'

Support new permission management via REST API

Closes #330

See merge request lava/lava!1005
parents fbeaa15a 74311ad0
......@@ -20,6 +20,8 @@
from lava_scheduler_app.models import (
Device,
DeviceType,
GroupDeviceTypePermission,
GroupDevicePermission,
TestJob,
Tag,
Architecture,
......@@ -30,7 +32,7 @@ from lava_scheduler_app.models import (
Core,
JobFailureTag,
)
from django.contrib.auth.models import User, Group
from django.contrib.auth.models import User, Group, Permission
from django.core.exceptions import ValidationError
from django_filters.filters import CharFilter
......@@ -65,6 +67,21 @@ class UserFilter(filters.FilterSet):
}
class PermissionFilter(filters.FilterSet):
class Meta:
model = Permission
fields = {
"codename": [
"exact",
"in",
"contains",
"icontains",
"startswith",
"endswith",
]
}
class ArchitectureFilter(filters.FilterSet):
class Meta:
model = Architecture
......@@ -386,3 +403,31 @@ class TestJobFilter(filters.FilterSet):
"isnull",
],
}
class GroupDeviceTypePermissionFilter(filters.FilterSet):
device_type = RelatedFilter(
DeviceTypeFilter, name="device_type", queryset=DeviceType.objects.all()
)
group = RelatedFilter(GroupFilter, name="group", queryset=Group.objects.all())
permission = RelatedFilter(
PermissionFilter, name="permission", queryset=Permission.objects.all()
)
class Meta:
model = GroupDeviceTypePermission
exclude = {}
class GroupDevicePermissionFilter(filters.FilterSet):
device = RelatedFilter(
DeviceFilter, name="device", queryset=DeviceType.objects.all()
)
group = RelatedFilter(GroupFilter, name="group", queryset=Group.objects.all())
permission = RelatedFilter(
PermissionFilter, name="permission", queryset=Permission.objects.all()
)
class Meta:
model = GroupDevicePermission
exclude = {}
......@@ -36,5 +36,7 @@ router.register(r"jobs", views.TestJobViewSet).register(
base_name="suites-test",
parents_query_lookups=["suite__job_id", "suite_id"],
)
router.register(r"permissions/devicetypes", views.GroupDeviceTypePermissionViewSet)
router.register(r"permissions/devices", views.GroupDevicePermissionViewSet)
router.register(r"tags", views.TagViewSet)
router.register(r"workers", views.WorkerViewSet)
......@@ -18,8 +18,17 @@
# along with LAVA. If not, see <http://www.gnu.org/licenses/>.
from django.contrib.auth.models import Group, Permission
from lava_rest_app.base import serializers as base_serializers
from lava_scheduler_app.models import Alias, Device, Tag
from lava_scheduler_app.models import (
Alias,
Device,
DeviceType,
GroupDeviceTypePermission,
GroupDevicePermission,
Tag,
)
from rest_framework_extensions.fields import ResourceUriField
from rest_framework.reverse import reverse as rest_reverse
......@@ -128,3 +137,35 @@ class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = "__all__"
class GroupDeviceTypePermissionSerializer(serializers.ModelSerializer):
group = serializers.SlugRelatedField(
slug_field="name", queryset=Group.objects.all()
)
permission = serializers.SlugRelatedField(
queryset=Permission.objects.filter(
content_type__model=DeviceType._meta.object_name.lower()
),
slug_field="codename",
)
class Meta:
model = GroupDeviceTypePermission
fields = "__all__"
class GroupDevicePermissionSerializer(serializers.ModelSerializer):
group = serializers.SlugRelatedField(
slug_field="name", queryset=Group.objects.all()
)
permission = serializers.SlugRelatedField(
queryset=Permission.objects.filter(
content_type__model=Device._meta.object_name.lower()
),
slug_field="codename",
)
class Meta:
model = GroupDevicePermission
fields = "__all__"
......@@ -53,6 +53,8 @@ from lava_scheduler_app.models import (
Device,
DeviceType,
DevicesUnavailableException,
GroupDeviceTypePermission,
GroupDevicePermission,
Tag,
)
......@@ -570,3 +572,27 @@ class TagViewSet(viewsets.ModelViewSet):
def get_queryset(self):
return self.queryset.all()
class GroupDeviceTypePermissionViewSet(viewsets.ModelViewSet):
queryset = GroupDeviceTypePermission.objects
serializer_class = serializers.GroupDeviceTypePermissionSerializer
filter_fields = "__all__"
filter_class = filters.GroupDeviceTypePermissionFilter
ordering_fields = "__all__"
permission_classes = [base_views.IsSuperUser]
def get_queryset(self):
return self.queryset.all()
class GroupDevicePermissionViewSet(viewsets.ModelViewSet):
queryset = GroupDevicePermission.objects
serializer_class = serializers.GroupDevicePermissionSerializer
filter_fields = "__all__"
filter_class = filters.GroupDevicePermissionFilter
ordering_fields = "__all__"
permission_classes = [base_views.IsSuperUser]
def get_queryset(self):
return self.queryset.all()
......@@ -35,6 +35,7 @@ from lava_scheduler_app.models import (
Device,
DeviceType,
GroupDeviceTypePermission,
GroupDevicePermission,
Tag,
TestJob,
Worker,
......@@ -129,6 +130,9 @@ class TestRestApi:
GroupDeviceTypePermission.objects.assign_perm(
DeviceType.VIEW_PERMISSION, self.group1, self.restricted_device_type1
)
GroupDeviceTypePermission.objects.assign_perm(
DeviceType.CHANGE_PERMISSION, self.group1, self.restricted_device_type1
)
self.invisible_device_type1 = DeviceType.objects.create(
name="invisible_device_type1", display=False
)
......@@ -155,6 +159,17 @@ class TestRestApi:
health=Device.HEALTH_RETIRED,
worker_host=self.worker2,
)
self.restricted_device1 = Device.objects.create(
hostname="restricted_device1",
device_type=self.restricted_device_type1,
worker_host=self.worker1,
)
GroupDevicePermission.objects.assign_perm(
Device.VIEW_PERMISSION, self.group1, self.restricted_device1
)
GroupDevicePermission.objects.assign_perm(
Device.CHANGE_PERMISSION, self.group1, self.restricted_device1
)
# create testjobs
self.public_testjob1 = TestJob.objects.create(
......@@ -494,9 +509,12 @@ ok 2 bar
self.adminclient,
reverse("api-root", args=[self.version]) + "devices/?ordering=hostname",
)
assert len(data["results"]) == 2 # nosec - unit test support
assert len(data["results"]) == 3 # nosec - unit test support
assert data["results"][0]["hostname"] == "public01" # nosec - unit test support
assert data["results"][1]["hostname"] == "public02" # nosec - unit test support
assert (
data["results"][2]["hostname"] == "restricted_device1"
) # nosec - unit test support
def test_devices_retrieve(self):
data = self.hit(
......@@ -1161,6 +1179,125 @@ ok 2 bar
)
assert response.status_code == 204 # nosec - unit test support
def test_devicetype_permissions_list_unauthorized(self):
response = self.userclient.get(
reverse("api-root", args=[self.version]) + "permissions/devicetypes/"
)
assert response.status_code == 403 # nosec - unit test support
def test_devicetype_permissions_list(self):
data = self.hit(
self.adminclient,
reverse("api-root", args=[self.version])
+ "permissions/devicetypes/?ordering=id",
)
assert len(data["results"]) == 2 # nosec - unit test support
assert (
data["results"][0]["devicetype"] == "restricted_device_type1"
) # nosec - unit test support
def test_devicetype_permissions_retrieve_unauthorized(self):
response = self.userclient.get(
reverse("api-root", args=[self.version]) + "permissions/devicetypes/1/"
)
assert response.status_code == 403 # nosec - unit test support
def test_devicetype_permissions_retrieve(self):
data = self.hit(
self.adminclient,
reverse("api-root", args=[self.version])
+ "permissions/devicetypes/%s/"
% GroupDeviceTypePermission.objects.first().id,
)
assert (
data["id"] == GroupDeviceTypePermission.objects.first().id
) # nosec - unit test support
assert (
data["devicetype"] == "restricted_device_type1"
) # nosec - unit test support
def test_devicetype_permissions_create(self):
response = self.adminclient.post(
reverse("api-root", args=[self.version]) + "permissions/devicetypes/",
{
"group": "group1",
"devicetype": "public_device_type1",
"permission": "view_devicetype",
},
)
assert response.status_code == 201 # nosec - unit test support
def test_devicetype_permissions_delete_unauthorized(self):
response = self.userclient.delete(
reverse("api-root", args=[self.version])
+ "permissions/devicetypes/%s/"
% GroupDeviceTypePermission.objects.first().id
)
assert response.status_code == 403 # nosec - unit test support
def test_devicetype_permissions_delete(self):
response = self.adminclient.delete(
reverse("api-root", args=[self.version])
+ "permissions/devicetypes/%s/"
% GroupDeviceTypePermission.objects.first().id
)
assert response.status_code == 204 # nosec - unit test support
def test_device_permissions_list_unauthorized(self):
response = self.userclient.get(
reverse("api-root", args=[self.version]) + "permissions/devices/"
)
assert response.status_code == 403 # nosec - unit test support
def test_device_permissions_list(self):
data = self.hit(
self.adminclient,
reverse("api-root", args=[self.version])
+ "permissions/devices/?ordering=id",
)
assert len(data["results"]) == 2 # nosec - unit test support
assert (
data["results"][0]["device"] == "restricted_device1"
) # nosec - unit test support
def test_device_permissions_retrieve_unauthorized(self):
response = self.userclient.get(
reverse("api-root", args=[self.version]) + "permissions/devices/1/"
)
assert response.status_code == 403 # nosec - unit test support
def test_device_permissions_retrieve(self):
data = self.hit(
self.adminclient,
reverse("api-root", args=[self.version])
+ "permissions/devices/%s/" % GroupDevicePermission.objects.first().id,
)
assert (
data["id"] == GroupDevicePermission.objects.first().id
) # nosec - unit test support
assert data["device"] == "restricted_device1" # nosec - unit test support
def test_device_permissions_create(self):
response = self.adminclient.post(
reverse("api-root", args=[self.version]) + "permissions/devices/",
{"group": "group1", "device": "public01", "permission": "view_device"},
)
assert response.status_code == 201 # nosec - unit test support
def test_device_permissions_delete_unauthorized(self):
response = self.userclient.delete(
reverse("api-root", args=[self.version])
+ "permissions/devices/%s/" % GroupDevicePermission.objects.first().id
)
assert response.status_code == 403 # nosec - unit test support
def test_device_permissions_delete(self):
response = self.adminclient.delete(
reverse("api-root", args=[self.version])
+ "permissions/devices/%s/" % GroupDevicePermission.objects.first().id
)
assert response.status_code == 204 # nosec - unit test support
def test_view_root(client):
ret = client.get(reverse("api-root", args=[versions.versions[-1]]) + "?format=api")
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment