diff --git a/awx/api/views.py b/awx/api/views.py index eebc1f7b24..5c177dbebf 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -2405,6 +2405,21 @@ class AdHocCommandRelaunch(GenericAPIView): if not request.user.can_access(self.model, 'start', obj): raise PermissionDenied() + # Re-validate ad hoc command against serializer to check if module is + # still allowed. + data = {} + for field in ('job_type', 'inventory_id', 'limit', 'credential_id', + 'module_name', 'module_args', 'forks', 'verbosity', + 'become_enabled'): + if field.endswith('_id'): + data[field[:-3]] = getattr(obj, field) + else: + data[field] = getattr(obj, field) + serializer = self.get_serializer(data=data) + if not serializer.is_valid(): + return Response(serializer.errors, + status=status.HTTP_400_BAD_REQUEST) + # Check for passwords needed before copying ad hoc command. needed = obj.passwords_needed_to_start provided = dict([(field, request.DATA.get(field, '')) for field in needed]) diff --git a/awx/main/tests/ad_hoc.py b/awx/main/tests/ad_hoc.py index 581981f5d7..b5155ed155 100644 --- a/awx/main/tests/ad_hoc.py +++ b/awx/main/tests/ad_hoc.py @@ -719,6 +719,14 @@ class AdHocCommandApiTest(BaseAdHocCommandTest): self.patch(url, {}, expect=401) self.delete(url, expect=401) + # Try to relaunch ad hoc command when module has been removed from + # allowed list of modules. + with self.settings(AD_HOC_COMMANDS=[]): + with self.current_user('admin'): + response = self.get(url, expect=200) + self.assertEqual(response['passwords_needed_to_start'], []) + response = self.post(url, {}, expect=400) + # Try to relaunch after the inventory has been marked inactive. self.inventory.mark_inactive() with self.current_user('admin'):