diff --git a/awx/main/tests/functional/api/test_settings.py b/awx/main/tests/functional/api/test_settings.py index 55fc45a334..b3487e237e 100644 --- a/awx/main/tests/functional/api/test_settings.py +++ b/awx/main/tests/functional/api/test_settings.py @@ -44,6 +44,27 @@ def test_license_cannot_be_removed_via_system_settings(mock_no_license_file, get assert response.data['LICENSE'] +@pytest.mark.django_db +def test_ldap_settings(get, put, patch, delete, admin, enterprise_license): + url = reverse('api:setting_singleton_detail', args=('ldap',)) + get(url, user=admin, expect=404) + Setting.objects.create(key='LICENSE', value=enterprise_license) + response = get(url, user=admin, expect=200) + # The PUT below will fail at the moment because AUTH_LDAP_GROUP_TYPE + # defaults to None but cannot be set to None. + # put(url, user=admin, data=response.data, expect=200) + delete(url, user=admin, expect=204) + patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': ''}, expect=200) + patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldap.example.com'}, expect=400) + patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldap://ldap.example.com'}, expect=200) + patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldaps://ldap.example.com'}, expect=200) + patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldap://ldap.example.com:389'}, expect=200) + patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldaps://ldap.example.com:636'}, expect=200) + patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldap://ldap.example.com ldap://ldap2.example.com'}, expect=200) + patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldap://ldap.example.com,ldap://ldap2.example.com'}, expect=200) + patch(url, user=admin, data={'AUTH_LDAP_SERVER_URI': 'ldap://ldap.example.com, ldap://ldap2.example.com'}, expect=200) + + @pytest.mark.django_db def test_ui_settings(get, put, patch, delete, admin, enterprise_license): url = reverse('api:setting_singleton_detail', args=('ui',)) diff --git a/awx/sso/conf.py b/awx/sso/conf.py index 4acf2e1f85..0a6642d953 100644 --- a/awx/sso/conf.py +++ b/awx/sso/conf.py @@ -170,15 +170,14 @@ register( register( 'AUTH_LDAP_SERVER_URI', - field_class=fields.URLField, - schemes=('ldap', 'ldaps'), + field_class=fields.LDAPServerURIField, allow_blank=True, default='', label=_('LDAP Server URI'), help_text=_('URI to connect to LDAP server, such as "ldap://ldap.example.com:389" ' - '(non-SSL) or "ldaps://ldap.example.com:636" (SSL). LDAP authentication ' - 'is disabled if this parameter is empty or your license does not ' - 'enable LDAP support.'), + '(non-SSL) or "ldaps://ldap.example.com:636" (SSL). Multiple LDAP ' + 'servers may be specified by separating with spaces or commas. LDAP ' + 'authentication is disabled if this parameter is empty.'), category=_('LDAP'), category_slug='ldap', placeholder='ldaps://ldap.example.com:636', diff --git a/awx/sso/fields.py b/awx/sso/fields.py index 874ec3acad..fdff68130f 100644 --- a/awx/sso/fields.py +++ b/awx/sso/fields.py @@ -105,6 +105,18 @@ class AuthenticationBackendsField(fields.StringListField): return backends +class LDAPServerURIField(fields.URLField): + + def __init__(self, **kwargs): + kwargs.setdefault('schemes', ('ldap', 'ldaps')) + super(LDAPServerURIField, self).__init__(**kwargs) + + def run_validators(self, value): + for url in filter(None, re.split(r'[, ]', (value or ''))): + super(LDAPServerURIField, self).run_validators(url) + return value + + class LDAPConnectionOptionsField(fields.DictField): default_error_messages = {