diff --git a/awx/api/views.py b/awx/api/views.py index 30bd034619..83919f007f 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -1755,6 +1755,10 @@ class JobTemplateLaunch(RetrieveAPIView, GenericAPIView): if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + # At this point, a credential is gauranteed to exist at serializer.object.credential + if not request.user.can_access(Credential, 'read', serializer.object.credential): + raise PermissionDenied() + kv = { 'credential': serializer.object.credential.pk, } diff --git a/awx/main/tests/jobs/job_launch.py b/awx/main/tests/jobs/job_launch.py index 69032102df..1e61aa611b 100644 --- a/awx/main/tests/jobs/job_launch.py +++ b/awx/main/tests/jobs/job_launch.py @@ -118,6 +118,13 @@ class JobTemplateLaunchTest(BaseJobTestMixin, django.test.TestCase): self.post(self.launch_url, {'credential': self.cred_doug.pk}, expect=400) self.post(self.launch_url, {'credential_id': self.cred_doug.pk}, expect=400) + def test_explicit_unowned_cred(self): + # Explicitly specify a credential that we don't have access to + with self.current_user(self.user_juan): + launch_url = reverse('api:job_template_launch', + args=(self.jt_eng_run.pk,)) + self.post(launch_url, {'credential_id': self.cred_sue.pk}, expect=403) + def test_no_project_fail(self): # Job Templates without projects can not be launched with self.current_user(self.user_sue):