From b99f211c7eeb91fa79ae5b4b3869035768702aa8 Mon Sep 17 00:00:00 2001 From: Ryan Petrello Date: Mon, 30 Jul 2018 13:36:37 -0400 Subject: [PATCH] add some additional validation to JT.credentials see: https://github.com/ansible/tower/issues/2612 --- awx/api/serializers.py | 4 ++++ awx/api/views.py | 3 +++ .../test_deprecated_credential_assignment.py | 23 ++++++++++++++++++- .../tests/functional/api/test_job_template.py | 23 ++++++++++++++++++- 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 1a2d648337..0c86f6a5ba 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -4285,6 +4285,10 @@ class JobLaunchSerializer(BaseSerializer): errors.setdefault('credentials', []).append(_( 'Cannot assign multiple {} credentials.' ).format(cred.unique_hash(display=True))) + if cred.credential_type.kind not in ('ssh', 'vault', 'cloud', 'net'): + errors.setdefault('credentials', []).append(_( + 'Cannot assign a Credential of kind `{}`' + ).format(cred.credential_type.kind)) distinct_cred_kinds.append(cred.unique_hash()) # Prohibit removing credentials from the JT list (unsupported for now) diff --git a/awx/api/views.py b/awx/api/views.py index d7928218b4..fc92ed1ac3 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -3346,6 +3346,9 @@ class JobTemplateCredentialsList(SubListCreateAttachDetachAPIView): if sub.unique_hash() in [cred.unique_hash() for cred in parent.credentials.all()]: return {"error": _("Cannot assign multiple {credential_type} credentials.".format( credential_type=sub.unique_hash(display=True)))} + kind = sub.credential_type.kind + if kind not in ('ssh', 'vault', 'cloud', 'net'): + return {'error': _('Cannot assign a Credential of kind `{}`.').format(kind)} return super(JobTemplateCredentialsList, self).is_valid_relation(parent, sub, created) diff --git a/awx/main/tests/functional/api/test_deprecated_credential_assignment.py b/awx/main/tests/functional/api/test_deprecated_credential_assignment.py index 8dbb3a391c..8beaddd391 100644 --- a/awx/main/tests/functional/api/test_deprecated_credential_assignment.py +++ b/awx/main/tests/functional/api/test_deprecated_credential_assignment.py @@ -2,7 +2,7 @@ import json import mock import pytest -from awx.main.models import Credential, Job +from awx.main.models import Credential, CredentialType, Job from awx.api.versioning import reverse @@ -151,6 +151,27 @@ def test_prevent_multiple_machine_creds(get, post, job_template, admin, machine_ assert 'Cannot assign multiple Machine credentials.' in resp.content +@pytest.mark.django_db +@pytest.mark.parametrize('kind', ['scm', 'insights']) +def test_invalid_credential_type_at_launch(get, post, job_template, admin, kind): + cred_type = CredentialType.defaults[kind]() + cred_type.save() + cred = Credential( + name='Some Cred', + credential_type=cred_type, + inputs={ + 'username': 'bob', + 'password': 'secret', + } + ) + cred.save() + url = reverse('api:job_template_launch', kwargs={'pk': job_template.pk}) + + resp = post(url, {'credentials': [cred.pk]}, admin, expect=400) + assert 'Cannot assign a Credential of kind `{}`'.format(kind) in resp.data.get('credentials', []) + assert Job.objects.count() == 0 + + @pytest.mark.django_db def test_prevent_multiple_machine_creds_at_launch(get, post, job_template, admin, machine_credential): other_cred = Credential(credential_type=machine_credential.credential_type, name="Second", diff --git a/awx/main/tests/functional/api/test_job_template.py b/awx/main/tests/functional/api/test_job_template.py index f2e17cb2bc..c555aa75d4 100644 --- a/awx/main/tests/functional/api/test_job_template.py +++ b/awx/main/tests/functional/api/test_job_template.py @@ -6,7 +6,7 @@ import pytest # AWX from awx.api.serializers import JobTemplateSerializer from awx.api.versioning import reverse -from awx.main.models.jobs import Job, JobTemplate +from awx.main.models import Job, JobTemplate, CredentialType from awx.main.migrations import _save_password_keys as save_password_keys # Django @@ -182,6 +182,27 @@ def test_extra_credential_creation(get, post, organization_factory, job_template assert response.data.get('count') == 1 +@pytest.mark.django_db +@pytest.mark.parametrize('kind', ['scm', 'insights']) +def test_invalid_credential_kind_xfail(get, post, organization_factory, job_template_factory, kind): + objs = organization_factory("org", superusers=['admin']) + jt = job_template_factory("jt", organization=objs.organization, + inventory='test_inv', project='test_proj').job_template + + url = reverse('api:job_template_credentials_list', kwargs={'version': 'v2', 'pk': jt.pk}) + cred_type = CredentialType.defaults[kind]() + cred_type.save() + response = post(url, { + 'name': 'My Cred', + 'credential_type': cred_type.pk, + 'inputs': { + 'username': 'bob', + 'password': 'secret', + } + }, objs.superusers.admin, expect=400) + assert 'Cannot assign a Credential of kind `{}`.'.format(kind) in response.data.values() + + @pytest.mark.django_db def test_extra_credential_unique_type_xfail(get, post, organization_factory, job_template_factory, credentialtype_aws): objs = organization_factory("org", superusers=['admin'])