From 9737ab620c1c5c9f9cfe5c014c73a482e14179ea Mon Sep 17 00:00:00 2001 From: Jake McDermott Date: Tue, 30 Apr 2019 13:17:15 -0400 Subject: [PATCH] require url scheme for credential type url inputs This adds a url formatting type for credential input string fields The validator for this formatting type will throw an error if the provided url string doesn't have a url schema. --- awx/main/credential_plugins/aim.py | 1 + awx/main/credential_plugins/azure_kv.py | 1 + awx/main/credential_plugins/conjur.py | 1 + awx/main/credential_plugins/hashivault.py | 1 + awx/main/fields.py | 11 ++++++- .../tests/functional/api/test_credential.py | 31 +++++++++++++++++++ 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/awx/main/credential_plugins/aim.py b/awx/main/credential_plugins/aim.py index d59fcb639d..8fde480b73 100644 --- a/awx/main/credential_plugins/aim.py +++ b/awx/main/credential_plugins/aim.py @@ -15,6 +15,7 @@ aim_inputs = { 'id': 'url', 'label': _('CyberArk AIM URL'), 'type': 'string', + 'format': 'url', }, { 'id': 'app_id', 'label': _('Application ID'), diff --git a/awx/main/credential_plugins/azure_kv.py b/awx/main/credential_plugins/azure_kv.py index ee193974d0..77b7394b1f 100644 --- a/awx/main/credential_plugins/azure_kv.py +++ b/awx/main/credential_plugins/azure_kv.py @@ -10,6 +10,7 @@ azure_keyvault_inputs = { 'id': 'url', 'label': _('Vault URL (DNS Name)'), 'type': 'string', + 'format': 'url', }, { 'id': 'client', 'label': _('Client ID'), diff --git a/awx/main/credential_plugins/conjur.py b/awx/main/credential_plugins/conjur.py index e7bcf9c859..c2a60f72b6 100644 --- a/awx/main/credential_plugins/conjur.py +++ b/awx/main/credential_plugins/conjur.py @@ -16,6 +16,7 @@ conjur_inputs = { 'id': 'url', 'label': _('Conjur URL'), 'type': 'string', + 'format': 'url', }, { 'id': 'api_key', 'label': _('API Key'), diff --git a/awx/main/credential_plugins/hashivault.py b/awx/main/credential_plugins/hashivault.py index fefa46cbae..f82af720cf 100644 --- a/awx/main/credential_plugins/hashivault.py +++ b/awx/main/credential_plugins/hashivault.py @@ -14,6 +14,7 @@ base_inputs = { 'id': 'url', 'label': _('Server URL'), 'type': 'string', + 'format': 'url', 'help_text': _('The URL to the HashiCorp Vault'), }, { 'id': 'token', diff --git a/awx/main/fields.py b/awx/main/fields.py index 963723319d..ab97552e81 100644 --- a/awx/main/fields.py +++ b/awx/main/fields.py @@ -490,6 +490,15 @@ def format_ssh_private_key(value): return True +@JSONSchemaField.format_checker.checks('url') +def format_url(value): + if urllib.parse.urlparse(value).scheme == '': + raise jsonschema.exceptions.FormatError( + 'Invalid URL: Missing url scheme (http, https, etc.)' + ) + return True + + class DynamicCredentialInputField(JSONSchemaField): """ Used to validate JSON for @@ -722,7 +731,7 @@ class CredentialTypeInputField(JSONSchemaField): 'type': 'object', 'properties': { 'type': {'enum': ['string', 'boolean']}, - 'format': {'enum': ['ssh_private_key']}, + 'format': {'enum': ['ssh_private_key', 'url']}, 'choices': { 'type': 'array', 'minItems': 1, diff --git a/awx/main/tests/functional/api/test_credential.py b/awx/main/tests/functional/api/test_credential.py index 2cb287b044..abf4cdc682 100644 --- a/awx/main/tests/functional/api/test_credential.py +++ b/awx/main/tests/functional/api/test_credential.py @@ -1942,3 +1942,34 @@ def test_create_credential_missing_user_team_org_xfail(post, admin, credentialty admin ) assert response.status_code == 400 + + +@pytest.mark.django_db +def test_create_credential_with_missing_url_schema_xfail(post, organization, admin): + credential_type = CredentialType( + kind='test', + name='MyTestCredentialType', + inputs = { + 'fields': [{ + 'id': 'server_url', + 'label': 'Server Url', + 'type': 'string', + 'format': 'url' + }] + } + ) + credential_type.save() + + params = { + 'name': 'Second Best credential ever', + 'organization': organization.pk, + 'credential_type': credential_type.pk, + 'inputs': {'server_url': 'foo.com'} + } + endpoint = reverse('api:credential_list', kwargs={'version': 'v2'}) + response = post(endpoint, params, admin) + assert response.status_code == 400 + + params['inputs'] = {'server_url': 'http://foo.com'} + response = post(endpoint, params, admin) + assert response.status_code == 201