From b0cf05e9c78fe04f299999ac00bf03c2077c1839 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Wed, 4 Jan 2017 16:53:23 -0500 Subject: [PATCH 1/2] Lower scheduling access requirement to execute --- awx/main/access.py | 12 +++-- .../functional/test_rbac_job_templates.py | 49 ++++++++++++------- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/awx/main/access.py b/awx/main/access.py index 1de7049426..117ed853ce 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -353,7 +353,7 @@ class BaseAccess(object): # Shortcuts in certain cases by deferring to earlier property if display_method == 'schedule': - user_capabilities['schedule'] = user_capabilities['edit'] + user_capabilities['schedule'] = user_capabilities['start'] continue elif display_method == 'delete' and not isinstance(obj, (User, UnifiedJob)): user_capabilities['delete'] = user_capabilities['edit'] @@ -1912,11 +1912,17 @@ class ScheduleAccess(BaseAccess): @check_superuser def can_add(self, data): - return self.check_related('unified_job_template', UnifiedJobTemplate, data, mandatory=True) + return self.check_related('unified_job_template', UnifiedJobTemplate, data, role_field='execute_role', mandatory=True) @check_superuser def can_change(self, obj, data): - return self.check_related('unified_job_template', UnifiedJobTemplate, data, obj=obj, mandatory=True) + if self.check_related('unified_job_template', UnifiedJobTemplate, data, obj=obj, mandatory=True): + return True + if ('unified_job_template' in data and data['unified_job_template'] != obj.pk) or obj.created_by_id != self.user.id: + return False + # Users with execute role can modify the schedules they created + return self.check_related('unified_job_template', UnifiedJobTemplate, data, obj=obj, role_field='execute_role') + def can_delete(self, obj): return self.can_change(obj, {}) diff --git a/awx/main/tests/functional/test_rbac_job_templates.py b/awx/main/tests/functional/test_rbac_job_templates.py index ac545dafee..13e0da8e8c 100644 --- a/awx/main/tests/functional/test_rbac_job_templates.py +++ b/awx/main/tests/functional/test_rbac_job_templates.py @@ -259,22 +259,37 @@ def test_associate_label(label, user, job_template): @pytest.mark.django_db -def test_move_schedule_to_JT_no_access(job_template, rando): - schedule = Schedule.objects.create( - unified_job_template=job_template, - rrule='DTSTART:20151117T050000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1') - job_template.admin_role.members.add(rando) - jt2 = JobTemplate.objects.create(name="other-jt") - access = ScheduleAccess(rando) - assert not access.can_change(schedule, data=dict(unified_job_template=jt2.pk)) +class TestJobTemplateSchedules: + + rrule = 'DTSTART:20151117T050000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1' + rrule2 = 'DTSTART:20151117T050000Z RRULE:FREQ=WEEKLY;INTERVAL=1;COUNT=1' + + @pytest.fixture + def jt2(self): + return JobTemplate.objects.create(name="other-jt") + + def test_move_schedule_to_JT_no_access(self, job_template, rando, jt2): + schedule = Schedule.objects.create(unified_job_template=job_template, rrule=self.rrule) + job_template.admin_role.members.add(rando) + access = ScheduleAccess(rando) + assert not access.can_change(schedule, data=dict(unified_job_template=jt2.pk)) -@pytest.mark.django_db -def test_move_schedule_from_JT_no_access(job_template, rando): - schedule = Schedule.objects.create( - unified_job_template=job_template, - rrule='DTSTART:20151117T050000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1') - jt2 = JobTemplate.objects.create(name="other-jt") - jt2.admin_role.members.add(rando) - access = ScheduleAccess(rando) - assert not access.can_change(schedule, data=dict(unified_job_template=jt2.pk)) + def test_move_schedule_from_JT_no_access(self, job_template, rando, jt2): + schedule = Schedule.objects.create(unified_job_template=job_template, rrule=self.rrule) + jt2.admin_role.members.add(rando) + access = ScheduleAccess(rando) + assert not access.can_change(schedule, data=dict(unified_job_template=jt2.pk)) + + + def test_can_create_schedule_with_execute(self, job_template, rando): + job_template.execute_role.members.add(rando) + access = ScheduleAccess(rando) + assert access.can_add({'unified_job_template': job_template}) + + + def test_can_modify_ones_own_schedule(self, job_template, rando): + job_template.execute_role.members.add(rando) + schedule = Schedule.objects.create(unified_job_template=job_template, rrule=self.rrule, created_by=rando) + access = ScheduleAccess(rando) + assert access.can_change(schedule, {'rrule': self.rrule2}) From 9422e87f00595adf4a16d25ce738d90ca2cebbc3 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Thu, 5 Jan 2017 15:42:08 -0500 Subject: [PATCH 2/2] simplify schedule execute_role editing rule --- awx/main/access.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/awx/main/access.py b/awx/main/access.py index 117ed853ce..2026e8589d 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -1918,10 +1918,10 @@ class ScheduleAccess(BaseAccess): def can_change(self, obj, data): if self.check_related('unified_job_template', UnifiedJobTemplate, data, obj=obj, mandatory=True): return True - if ('unified_job_template' in data and data['unified_job_template'] != obj.pk) or obj.created_by_id != self.user.id: - return False # Users with execute role can modify the schedules they created - return self.check_related('unified_job_template', UnifiedJobTemplate, data, obj=obj, role_field='execute_role') + return ( + obj.created_by == self.user and + self.check_related('unified_job_template', UnifiedJobTemplate, data, obj=obj, role_field='execute_role', mandatory=True)) def can_delete(self, obj):