Commit b7c4ada0 authored by Stevan Radakovic's avatar Stevan Radakovic
Browse files

Reorganize the django permissions and custom permissions.

Remove old permissions like dashboard_add, android_banchmark_views_app etc
Merge admin_device into change_device permissions
Merge admin_devicetype into change_devicetype permissions
Remove add_testjob permission
Merge admin_testjob, cancel_resubmit_testjob into change_testjob permission
parent 75a38544
......@@ -656,7 +656,7 @@ class SchedulerAPI(ExposedAPI):
device = Device.objects.select_for_update().get(hostname=hostname)
except Device.DoesNotExist:
raise xmlrpc.client.Fault(404, "Device '%s' was not found." % hostname)
if device.can_admin(self.user):
if device.can_change(self.user):
device.health = Device.HEALTH_MAINTENANCE
device.save()
else:
......@@ -703,7 +703,7 @@ class SchedulerAPI(ExposedAPI):
device = Device.objects.select_for_update().get(hostname=hostname)
except Device.DoesNotExist:
raise xmlrpc.client.Fault(404, "Device '%s' was not found." % hostname)
if device.can_admin(self.user):
if device.can_change(self.user):
device.health = Device.HEALTH_UNKNOWN
device.save()
else:
......@@ -1136,7 +1136,7 @@ class SchedulerAPI(ExposedAPI):
Description
-----------
[user with admin_device permission only]
[user with change_device permission only]
Import or update the device dictionary key value store for a
pipeline device.
......@@ -1156,7 +1156,7 @@ class SchedulerAPI(ExposedAPI):
device = Device.objects.get(hostname=hostname)
except DeviceType.DoesNotExist:
raise xmlrpc.client.Fault(404, "Device '%s' was not found." % hostname)
if device.can_admin(self.user):
if device.can_change(self.user):
if not device.save_configuration(jinja_str):
raise xmlrpc.client.Fault(
400, "Unable to store the configuration for %s on disk" % hostname
......@@ -1198,7 +1198,7 @@ class SchedulerAPI(ExposedAPI):
device = Device.objects.get(hostname=hostname)
except DeviceType.DoesNotExist:
raise xmlrpc.client.Fault(404, "Device '%s' was not found." % hostname)
if device.can_admin(self.user):
if device.can_change(self.user):
device_dict = device.load_configuration(output_format="raw")
if not device_dict:
raise xmlrpc.client.Fault(
......
......@@ -43,7 +43,7 @@ class SchedulerDeviceTypesAPI(ExposedV2API):
available_types.sort()
return available_types
@check_perm("lava_scheduler_app.admin_devicetype")
@check_perm("lava_scheduler_app.change_devicetype")
def add(
self,
name,
......@@ -199,7 +199,7 @@ class SchedulerDeviceTypesAPI(ExposedV2API):
400, "Unable to read device-type configuration: %s" % exc.strerror
)
@check_perm("lava_scheduler_app.admin_devicetype")
@check_perm("lava_scheduler_app.change_devicetype")
def set_health_check(self, name, config):
"""
Name
......@@ -244,7 +244,7 @@ class SchedulerDeviceTypesAPI(ExposedV2API):
400, "Unable to write health-check: %s" % exc.strerror
)
@check_perm("lava_scheduler_app.admin_devicetype")
@check_perm("lava_scheduler_app.change_devicetype")
def set_template(self, name, config):
"""
Name
......@@ -431,7 +431,7 @@ class SchedulerDeviceTypesAPI(ExposedV2API):
dt = DeviceType.objects.get(name=name)
except DeviceType.DoesNotExist:
raise xmlrpc.client.Fault(404, "Device-type '%s' was not found." % name)
if not dt.can_admin(self.user):
if not dt.can_change(self.user):
raise xmlrpc.client.Fault(
403, "No 'admin' permissions for device-type '%s'." % name
)
......@@ -491,7 +491,7 @@ class SchedulerDeviceTypesAliasesAPI(ExposedV2API):
dt = DeviceType.objects.get(name=name)
except DeviceType.DoesNotExist:
raise xmlrpc.client.Fault(404, "Device-type '%s' was not found." % name)
if not dt.can_admin(self.user):
if not dt.can_change(self.user):
raise xmlrpc.client.Fault(
403, "No 'admin' permissions for device-type '%s'." % name
)
......@@ -551,7 +551,7 @@ class SchedulerDeviceTypesAliasesAPI(ExposedV2API):
dt = DeviceType.objects.get(name=name)
except DeviceType.DoesNotExist:
raise xmlrpc.client.Fault(404, "Device-type '%s' was not found." % name)
if not dt.can_admin(self.user):
if not dt.can_change(self.user):
raise xmlrpc.client.Fault(
403, "No 'admin' permissions for device-type '%s'." % name
)
......
......@@ -29,7 +29,7 @@ from lava_scheduler_app.models import Device, DeviceType, Tag, Worker
class SchedulerDevicesAPI(ExposedV2API):
@check_perm("lava_scheduler_app.admin_device")
@check_perm("lava_scheduler_app.change_device")
def add(
self,
hostname,
......@@ -192,7 +192,7 @@ class SchedulerDevicesAPI(ExposedV2API):
except Device.DoesNotExist:
raise xmlrpc.client.Fault(404, "Device '%s' was not found." % hostname)
if not device.can_admin(self.user):
if not device.can_change(self.user):
raise xmlrpc.client.Fault(
403,
"User '%s' needs admin permission on device %s."
......@@ -346,7 +346,7 @@ class SchedulerDevicesAPI(ExposedV2API):
with transaction.atomic():
device = Device.objects.get(hostname=hostname)
if not device.can_admin(self.user):
if not device.can_change(self.user):
raise xmlrpc.client.Fault(
403,
"User '%s' needs admin permission on device %s."
......@@ -413,7 +413,7 @@ class SchedulerDevicesTagsAPI(ExposedV2API):
device = Device.objects.get(hostname=hostname)
except Device.DoesNotExist:
raise xmlrpc.client.Fault(404, "Device '%s' was not found." % hostname)
if not device.can_admin(self.user):
if not device.can_change(self.user):
raise xmlrpc.client.Fault(
403,
"User '%s' needs admin permission on device %s."
......@@ -475,7 +475,7 @@ class SchedulerDevicesTagsAPI(ExposedV2API):
except Device.DoesNotExist:
raise xmlrpc.client.Fault(404, "Device '%s' was not found." % hostname)
if not device.can_admin(self.user):
if not device.can_change(self.user):
raise xmlrpc.client.Fault(
403,
"User '%s' needs admin permission on device %s."
......
# -*- coding: utf-8 -*-
# Generated by Django 1.11.23 on 2019-10-12 16:54
from __future__ import unicode_literals
from django.db import migrations, transaction
from django.db.utils import IntegrityError
def forwards_func(apps, schema_editor):
DeviceType = apps.get_model("lava_scheduler_app", "DeviceType")
Device = apps.get_model("lava_scheduler_app", "Device")
TestJob = apps.get_model("lava_scheduler_app", "TestJob")
User = apps.get_model("auth", "User")
Group = apps.get_model("auth", "Group")
Permission = apps.get_model("auth", "Permission")
ContentType = apps.get_model("contenttypes", "ContentType")
GroupDeviceTypePermission = apps.get_model(
"lava_scheduler_app", "GroupDeviceTypePermission"
)
GroupDevicePermission = apps.get_model(
"lava_scheduler_app", "GroupDevicePermission"
)
db_alias = schema_editor.connection.alias
ct_devicetype = ContentType.objects.get_for_model(DeviceType)
ct_device = ContentType.objects.get_for_model(Device)
ct_testjob = ContentType.objects.get_for_model(TestJob)
admin_devicetype_perm, _ = Permission.objects.using(db_alias).get_or_create(
name="Can admin device type",
content_type=ct_devicetype,
codename="admin_devicetype",
)
change_devicetype_perm, _ = Permission.objects.using(db_alias).get_or_create(
name="Can change device type",
content_type=ct_devicetype,
codename="change_devicetype",
)
admin_device_perm, _ = Permission.objects.using(db_alias).get_or_create(
name="Can admin device", content_type=ct_device, codename="admin_device"
)
change_device_perm, _ = Permission.objects.using(db_alias).get_or_create(
name="Can change device", content_type=ct_device, codename="change_device"
)
try:
cancel_resubmit_testjob_perm = Permission.objects.using(db_alias).get(
content_type=ct_testjob, codename="cancel_resubmit_testjob"
)
except Permission.DoesNotExist:
cancel_resubmit_testjob_perm = Permission.objects.using(db_alias).create(
name="Can cancel or resubmit test jobs",
content_type=ct_testjob,
codename="cancel_resubmit_testjob",
)
change_testjob_perm, _ = Permission.objects.using(db_alias).get_or_create(
name="Can change test job", content_type=ct_testjob, codename="change_testjob"
)
obsolete_content_type_apps = [
"dashboard_app",
"linaro_graphics_app",
"south",
"lava_projects",
"lava_kernel_ci_views_app",
"djcelery",
"android_benchmark_views_app",
]
obsolete_cts = ContentType.objects.filter(app_label__in=obsolete_content_type_apps)
Permission.objects.using(db_alias).filter(content_type__in=obsolete_cts).delete()
for group in Group.objects.using(db_alias).all():
if group.permissions.filter(codename="admin_devicetype"):
group.permissions.add(change_devicetype_perm)
group.permissions.remove(admin_devicetype_perm)
if group.permissions.filter(codename="admin_device"):
group.permissions.add(change_device_perm)
group.permissions.remove(admin_device_perm)
if group.permissions.filter(codename="cancel_resubmit_testjob"):
group.permissions.add(change_testjob_perm)
group.permissions.remove(cancel_resubmit_testjob_perm)
for user in User.objects.using(db_alias).all():
if user.user_permissions.filter(codename="admin_devicetype"):
user.user_permissions.add(change_devicetype_perm)
user.user_permissions.remove(admin_devicetype_perm)
if user.user_permissions.filter(codename="admin_device"):
user.user_permissions.add(change_device_perm)
user.user_permissions.remove(admin_device_perm)
if user.user_permissions.filter(codename="cancel_resubmit_testjob"):
user.user_permissions.add(change_testjob_perm)
user.user_permissions.remove(cancel_resubmit_testjob_perm)
for group_permission in GroupDeviceTypePermission.objects.using(db_alias).filter(
permission=admin_devicetype_perm
):
try:
with transaction.atomic():
group_permission.permission = change_devicetype_perm
group_permission.save()
except IntegrityError:
group_permission.delete()
for group_permission in GroupDevicePermission.objects.using(db_alias).filter(
permission=admin_device_perm
):
try:
with transaction.atomic():
group_permission.permission = change_device_perm
group_permission.save()
except IntegrityError:
group_permission.delete()
Permission.objects.using(db_alias).filter(codename="add_testjob").delete()
Permission.objects.using(db_alias).filter(codename="admin_devicetype").delete()
Permission.objects.using(db_alias).filter(codename="admin_device").delete()
def noop(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [("lava_scheduler_app", "0045_remove_submit_testjob_perm")]
operations = [
migrations.RunPython(forwards_func, noop),
migrations.AlterModelOptions(
name="device",
options={
"permissions": (
("view_device", "Can view device"),
("submit_to_device", "Can submit jobs to device"),
)
},
),
migrations.AlterModelOptions(
name="devicetype",
options={
"permissions": (
("view_devicetype", "Can view device type"),
("submit_to_devicetype", "Can submit jobs to device type"),
)
},
),
migrations.AlterModelOptions(
name="testjob", options={"default_permissions": ("change", "delete")}
),
]
......@@ -228,18 +228,15 @@ class DeviceType(RestrictedObject):
class Meta:
permissions = add_permissions(
(("view_devicetype", "Can view device type"),),
(
("submit_to_devicetype", "Can submit jobs to device type"),
("admin_devicetype", "Can admin device type"),
),
(("submit_to_devicetype", "Can submit jobs to device type"),),
)
VIEW_PERMISSION = "lava_scheduler_app.view_devicetype"
ADMIN_PERMISSION = "lava_scheduler_app.admin_devicetype"
CHANGE_PERMISSION = "lava_scheduler_app.change_devicetype"
SUBMIT_PERMISSION = "lava_scheduler_app.submit_to_devicetype"
# Order of permission importance from most to least.
PERMISSIONS_PRIORITY = [ADMIN_PERMISSION, SUBMIT_PERMISSION, VIEW_PERMISSION]
PERMISSIONS_PRIORITY = [CHANGE_PERMISSION, SUBMIT_PERMISSION, VIEW_PERMISSION]
objects = RestrictedDeviceTypeQuerySet.as_manager()
......@@ -347,8 +344,8 @@ class DeviceType(RestrictedObject):
return True
return False
def can_admin(self, user):
return user.has_perm(self.ADMIN_PERMISSION, self)
def can_change(self, user):
return user.has_perm(self.CHANGE_PERMISSION, self)
def has_any_permission_restrictions(self, perm):
return self.is_permission_restricted(perm)
......@@ -395,7 +392,7 @@ class Worker(models.Model):
def __str__(self):
return self.hostname
def can_admin(self, user):
def can_change(self, user):
return user.has_perm("lava_scheduler_app.change_worker")
def can_update(self, user):
......@@ -479,25 +476,22 @@ class Device(RestrictedObject):
class Meta:
permissions = add_permissions(
(("view_device", "Can view device"),),
(
("submit_to_device", "Can submit jobs to device"),
("admin_device", "Can admin device"),
),
(("submit_to_device", "Can submit jobs to device"),),
)
VIEW_PERMISSION = "lava_scheduler_app.view_device"
ADMIN_PERMISSION = "lava_scheduler_app.admin_device"
CHANGE_PERMISSION = "lava_scheduler_app.change_device"
SUBMIT_PERMISSION = "lava_scheduler_app.submit_to_device"
# This maps the corresponding permissions for 'parent' dependencies.
DEVICE_TYPE_PERMISSION_MAP = {
VIEW_PERMISSION: DeviceType.VIEW_PERMISSION,
ADMIN_PERMISSION: DeviceType.ADMIN_PERMISSION,
CHANGE_PERMISSION: DeviceType.CHANGE_PERMISSION,
SUBMIT_PERMISSION: DeviceType.SUBMIT_PERMISSION,
}
# Order of permission importance from most to least.
PERMISSIONS_PRIORITY = [ADMIN_PERMISSION, SUBMIT_PERMISSION, VIEW_PERMISSION]
PERMISSIONS_PRIORITY = [CHANGE_PERMISSION, SUBMIT_PERMISSION, VIEW_PERMISSION]
objects = RestrictedDeviceQuerySet.as_manager()
......@@ -651,11 +645,11 @@ class Device(RestrictedObject):
return True
return False
def can_admin(self, user):
if user.has_perm(self.ADMIN_PERMISSION, self):
def can_change(self, user):
if user.has_perm(self.CHANGE_PERMISSION, self):
return True
if not self.is_permission_restricted(self.ADMIN_PERMISSION):
if user.has_perm(self.device_type.ADMIN_PERMISSION, self.device_type):
if not self.is_permission_restricted(self.CHANGE_PERMISSION):
if user.has_perm(self.device_type.CHANGE_PERMISSION, self.device_type):
return True
return False
......@@ -1299,19 +1293,19 @@ class TestJob(models.Model):
class Meta:
index_together = ["health", "state", "requested_device_type"]
permissions = (("cancel_resubmit_testjob", "Can cancel or resubmit test jobs"),)
default_permissions = ("change", "delete")
# Permission strings. Not real permissions.
VIEW_PERMISSION = "lava_scheduler_app.view_testjob"
ADMIN_PERMISSION = "lava_scheduler_app.admin_testjob"
CHANGE_PERMISSION = "lava_scheduler_app.change_testjob"
# This maps the corresponding permissions for 'parent' dependencies.
DEVICE_PERMISSION_MAP = {
VIEW_PERMISSION: Device.VIEW_PERMISSION,
ADMIN_PERMISSION: Device.ADMIN_PERMISSION,
CHANGE_PERMISSION: Device.CHANGE_PERMISSION,
}
DEVICE_TYPE_PERMISSION_MAP = {
VIEW_PERMISSION: DeviceType.VIEW_PERMISSION,
ADMIN_PERMISSION: DeviceType.ADMIN_PERMISSION,
CHANGE_PERMISSION: DeviceType.CHANGE_PERMISSION,
}
objects = RestrictedTestJobQuerySet.as_manager()
......@@ -1785,13 +1779,13 @@ class TestJob(models.Model):
return False
def can_admin(self, user):
def can_change(self, user):
if user == self.submitter:
return True
if self.actual_device:
return self.actual_device.can_admin(user)
elif user.has_perm(DeviceType.ADMIN_PERMISSION, self.requested_device_type):
return self.actual_device.can_change(user)
elif user.has_perm(DeviceType.CHANGE_PERMISSION, self.requested_device_type):
return True
return False
......@@ -1803,7 +1797,7 @@ class TestJob(models.Model):
"""
if user == self.submitter:
return True
if self.can_admin(user):
if self.can_change(user):
return True
return False
......@@ -1814,7 +1808,7 @@ class TestJob(models.Model):
"""
if not self.state == TestJob.STATE_FINISHED:
return False
if not self.can_admin(user):
if not self.can_change(user):
return False
return True
......@@ -1826,15 +1820,13 @@ class TestJob(models.Model):
TestJob.STATE_SCHEDULED,
TestJob.STATE_RUNNING,
]
can_cancel = self.can_admin(user) or user.has_perm(
"lava_scheduler_app.cancel_resubmit_testjob"
can_cancel = self.can_change(user) or user.has_perm(
"lava_scheduler_app.change_testjob"
)
return can_cancel and self.state in states
def can_resubmit(self, user):
if self.can_admin(user) or user.has_perm(
"lava_scheduler_app.cancel_resubmit_testjob"
):
if self.can_change(user) or user.has_perm("lava_scheduler_app.change_testjob"):
return True
# Allow users who are able to submit to device or devicetype to also
......
......@@ -77,7 +77,7 @@
{% endif %}
{{ device.get_health_display }}
</span>
{% if can_admin %}
{% if can_change %}
&nbsp;<a href="#healthModal" data-toggle="modal" data-target="#healthModal"><span class="glyphicon glyphicon-pencil"></span></a>
<div class="modal fade" id="healthModal" tabindex="-1" role="dialog" aria-labelledby="healthModalLabel">
<div class="modal-dialog" role="document">
......
......@@ -45,7 +45,7 @@
{% endif %}
{{ worker.get_health_display }}
</span>
{% if can_admin %}
{% if can_change %}
&nbsp;<a href="#healthModal" data-toggle="modal" data-target="#healthModal"><span class="glyphicon glyphicon-pencil"></span></a>
<div class="modal fade" id="healthModal" tabindex="-1" role="dialog" aria-labelledby="healthModalLabel">
<div class="modal-dialog" role="document">
......
......@@ -65,11 +65,11 @@ class PermissionAuthTest(TestCaseWithFactory):
# Test group permission queries.
auth = PermissionAuth(self.user)
GroupDevicePermission.objects.assign_perm(
"admin_device", self.group, self.device
"change_device", self.group, self.device
)
permissions = auth.get_group_perms(self.device)
self.assertEqual(
permissions, {"admin_device", "view_device", "submit_to_device"}
permissions, {"change_device", "view_device", "submit_to_device"}
)
def test_anonymous_unrestricted_device_type(self):
......@@ -93,7 +93,7 @@ class PermissionAuthTest(TestCaseWithFactory):
guy_fawkes = AnonymousUser()
auth = PermissionAuth(guy_fawkes)
GroupDeviceTypePermission.objects.assign_perm(
"admin_devicetype", self.group, self.device_type
"change_devicetype", self.group, self.device_type
)
self.assertTrue(
auth.has_perm("lava_scheduler_app.view_devicetype", self.device_type)
......@@ -116,7 +116,7 @@ class PermissionAuthTest(TestCaseWithFactory):
guy_fawkes = AnonymousUser()
auth = PermissionAuth(guy_fawkes)
GroupDevicePermission.objects.assign_perm(
"admin_device", self.group, self.device
"change_device", self.group, self.device
)
self.assertTrue(auth.has_perm("lava_scheduler_app.view_device", self.device))
......@@ -169,13 +169,15 @@ class PermissionAuthTest(TestCaseWithFactory):
user = User.objects.create(username="notactive")
user.groups.add(self.group)
GroupDevicePermission.objects.assign_perm(
"admin_device", self.group, self.device
"change_device", self.group, self.device
)
check = PermissionAuth(user)
self.assertTrue(check.has_perm("lava_scheduler_app.admin_device", self.device))
self.assertTrue(check.has_perm("lava_scheduler_app.change_device", self.device))
user.is_active = False
self.assertFalse(check.has_perm("lava_scheduler_app.admin_device", self.device))
self.assertFalse(
check.has_perm("lava_scheduler_app.change_device", self.device)
)
def test_get_perms(self):
device1 = self.factory.make_device(
......@@ -185,7 +187,7 @@ class PermissionAuthTest(TestCaseWithFactory):
device_type=self.device_type, hostname="qemu-tmp-02"
)
assign_perms = {device1: ("admin_device",), device2: ("view_device",)}
assign_perms = {device1: ("change_device",), device2: ("view_device",)}
auth = PermissionAuth(self.user)
......
......@@ -54,10 +54,10 @@ class BackendAuthTest(TestCaseWithFactory):
set(self.backend.get_all_permissions(self.user, self.device)),
)
GroupDevicePermission.objects.assign_perm(
"admin_device", self.group, self.device
"change_device", self.group, self.device
)
self.assertEqual(
set(["admin_device", "submit_to_device", "view_device"]),
set(["change_device", "submit_to_device", "view_device"]),
set(self.backend.get_all_permissions(self.user, self.device)),
)
......@@ -69,20 +69,20 @@ class BackendAuthTest(TestCaseWithFactory):
set(self.backend.get_all_permissions(self.user, self.device_type)),
)
GroupDeviceTypePermission.objects.assign_perm(
"admin_devicetype", self.group, self.device_type
"change_devicetype", self.group, self.device_type
)
self.assertEqual(
set(["admin_devicetype", "view_devicetype", "submit_to_devicetype"]),
set(["change_devicetype", "view_devicetype", "submit_to_devicetype"]),
self.backend.get_all_permissions(self.user, self.device_type),
)
def test_has_perm(self):
GroupDevicePermission.objects.assign_perm(
"admin_device", self.group, self.device
"change_device", self.group, self.device
)
self.assertTrue(
self.backend.has_perm(
self.user, "lava_scheduler_app.admin_device", self.device
self.user, "lava_scheduler_app.change_device", self.device
)
)
self.assertTrue(
......@@ -98,13 +98,13 @@ class BackendAuthTest(TestCaseWithFactory):
def test_has_global_perm(self):
user = self.factory.make_user()
user.user_permissions.add(Permission.objects.get(codename="admin_device"))
user.user_permissions.add(Permission.objects.get(codename="change_device"))
self.assertTrue(
self.backend.has_perm(user, "lava_scheduler_app.admin_device", self.device)
self.backend.has_perm(user, "lava_scheduler_app.change_device", self.device)
)
def test_has_perm_wrong_app_label(self):
with TestCase.assertRaises(self, ValueError):
self.backend.has_perm(
self.user, "lava_results_app.admin_device", self.device
self.user, "lava_results_app.change_device", self.device