diff --git a/awx/api/filters.py b/awx/api/filters.py index b28c311e26..3fc44ce921 100644 --- a/awx/api/filters.py +++ b/awx/api/filters.py @@ -33,6 +33,18 @@ class MongoFilterBackend(BaseFilterBackend): return queryset +class V1CredentialFilterBackend(BaseFilterBackend): + ''' + For /api/v1/ requests, filter out v2 (custom) credentials + ''' + + def filter_queryset(self, request, queryset, view): + from awx.api.versioning import get_request_version + if get_request_version(request) == 1: + queryset = queryset.filter(credential_type__managed_by_tower=True) + return queryset + + class TypeFilterBackend(BaseFilterBackend): ''' Filter on type field now returned with all objects. diff --git a/awx/api/views.py b/awx/api/views.py index 836d2db869..61459c71b8 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -62,6 +62,7 @@ from awx.main.tasks import send_notifications from awx.main.access import get_user_queryset from awx.main.ha import is_ha_environment from awx.api.authentication import TaskAuthentication, TokenGetAuthentication +from awx.api.filters import V1CredentialFilterBackend from awx.api.generics import get_view_name from awx.api.generics import * # noqa from awx.api.versioning import reverse, get_request_version @@ -1507,6 +1508,7 @@ class CredentialList(ListCreateAPIView): model = Credential serializer_class = CredentialSerializerCreate capabilities_prefetch = ['admin', 'use'] + filter_backends = ListCreateAPIView.filter_backends + [V1CredentialFilterBackend] class CredentialOwnerUsersList(SubListAPIView): @@ -1542,6 +1544,7 @@ class UserCredentialsList(SubListCreateAPIView): serializer_class = UserCredentialSerializerCreate parent_model = User parent_key = 'user' + filter_backends = SubListCreateAPIView.filter_backends + [V1CredentialFilterBackend] def get_queryset(self): user = self.get_parent_object() @@ -1558,6 +1561,7 @@ class TeamCredentialsList(SubListCreateAPIView): serializer_class = TeamCredentialSerializerCreate parent_model = Team parent_key = 'team' + filter_backends = SubListCreateAPIView.filter_backends + [V1CredentialFilterBackend] def get_queryset(self): team = self.get_parent_object() @@ -1574,6 +1578,7 @@ class OrganizationCredentialList(SubListCreateAPIView): serializer_class = OrganizationCredentialSerializerCreate parent_model = Organization parent_key = 'organization' + filter_backends = SubListCreateAPIView.filter_backends + [V1CredentialFilterBackend] def get_queryset(self): organization = self.get_parent_object() @@ -1592,6 +1597,7 @@ class CredentialDetail(RetrieveUpdateDestroyAPIView): model = Credential serializer_class = CredentialSerializer + filter_backends = RetrieveUpdateDestroyAPIView.filter_backends + [V1CredentialFilterBackend] class CredentialActivityStreamList(ActivityStreamEnforcementMixin, SubListAPIView): diff --git a/awx/main/tests/functional/api/test_credential.py b/awx/main/tests/functional/api/test_credential.py index 2f1fdee97d..1c809b8e3f 100644 --- a/awx/main/tests/functional/api/test_credential.py +++ b/awx/main/tests/functional/api/test_credential.py @@ -33,6 +33,79 @@ def test_filter_by_v1_kind(get, admin, organization, kind, total): assert response.data['count'] == total +@pytest.mark.django_db +def test_custom_credentials_not_in_v1_api_list(get, admin, organization): + """ + 'Custom' credentials (those not managed by Tower) shouldn't be visible from + the V1 credentials API list + """ + credential_type = CredentialType( + kind='cloud', + name='MyCloud', + inputs = { + 'fields': [{ + 'id': 'password', + 'label': 'Password', + 'type': 'string', + 'secret': True + }] + } + ) + credential_type.save() + cred = Credential( + credential_type=credential_type, + name='Best credential ever', + organization=organization, + inputs={ + 'password': u'secret' + } + ) + cred.save() + + response = get( + reverse('api:credential_list', kwargs={'version': 'v1'}), + admin + ) + assert response.status_code == 200 + assert response.data['count'] == 0 + + +@pytest.mark.django_db +def test_custom_credentials_not_in_v1_api_detail(get, admin, organization): + """ + 'Custom' credentials (those not managed by Tower) shouldn't be visible from + the V1 credentials API detail + """ + credential_type = CredentialType( + kind='cloud', + name='MyCloud', + inputs = { + 'fields': [{ + 'id': 'password', + 'label': 'Password', + 'type': 'string', + 'secret': True + }] + } + ) + credential_type.save() + cred = Credential( + credential_type=credential_type, + name='Best credential ever', + organization=organization, + inputs={ + 'password': u'secret' + } + ) + cred.save() + + response = get( + reverse('api:credential_detail', kwargs={'version': 'v1', 'pk': cred.pk}), + admin + ) + assert response.status_code == 404 + + @pytest.mark.django_db def test_filter_by_v1_invalid_kind(get, admin, organization): response = get(