summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--awx/main/backend.py36
-rw-r--r--awx/main/tests/__init__.py2
-rw-r--r--awx/main/tests/users.py71
-rw-r--r--awx/settings/defaults.py11
-rw-r--r--awx/settings/local_settings.py.example60
-rw-r--r--config/deb/settings.py28
-rw-r--r--config/rpm/settings.py28
7 files changed, 235 insertions, 1 deletions
diff --git a/awx/main/backend.py b/awx/main/backend.py
new file mode 100644
index 0000000000..86a06ae051
--- /dev/null
+++ b/awx/main/backend.py
@@ -0,0 +1,36 @@
+# Copyright (c) 2013 AnsibleWorks, Inc.
+# All Rights Reserved.
+
+# django-auth-ldap
+from django_auth_ldap.backend import LDAPBackend as BaseLDAPBackend
+
+class LDAPBackend(BaseLDAPBackend):
+ '''
+ Custom LDAP backend for AWX.
+ '''
+
+ settings_prefix = 'AUTH_LDAP_'
+
+ def authenticate(self, username, password):
+ if not self.settings.SERVER_URI:
+ return None
+ return super(LDAPBackend, self).authenticate(username, password)
+
+ def get_user(self, user_id):
+ if not self.settings.SERVER_URI:
+ return None
+ return super(LDAPBackend, self).get_user(user_id)
+
+ # Disable any LDAP based authorization / permissions checking.
+
+ def has_perm(self, user, perm, obj=None):
+ return False
+
+ def has_module_perms(self, user, app_label):
+ return False
+
+ def get_all_permissions(self, user, obj=None):
+ return set()
+
+ def get_group_permissions(self, user, obj=None):
+ return set()
diff --git a/awx/main/tests/__init__.py b/awx/main/tests/__init__.py
index 985bda16e1..bd12cbff90 100644
--- a/awx/main/tests/__init__.py
+++ b/awx/main/tests/__init__.py
@@ -2,7 +2,7 @@
# All Rights Reserved.
from awx.main.tests.organizations import OrganizationsTest
-from awx.main.tests.users import UsersTest
+from awx.main.tests.users import *
from awx.main.tests.inventory import InventoryTest
from awx.main.tests.projects import ProjectsTest, ProjectUpdatesTest
from awx.main.tests.commands import *
diff --git a/awx/main/tests/users.py b/awx/main/tests/users.py
index 2c05ad3a2c..1bad7f4591 100644
--- a/awx/main/tests/users.py
+++ b/awx/main/tests/users.py
@@ -7,15 +7,21 @@ import json
import urllib
# Django
+from django.conf import settings, UserSettingsHolder
from django.contrib.auth.models import User
import django.test
from django.test.client import Client
from django.core.urlresolvers import reverse
+# Django-Auth-LDAP
+from django_auth_ldap.backend import LDAPSettings
+
# AWX
from awx.main.models import *
from awx.main.tests.base import BaseTest
+__all__ = ['UsersTest', 'LdapTest']
+
class UsersTest(BaseTest):
def collection(self):
@@ -621,3 +627,68 @@ class UsersTest(BaseTest):
self.check_get_list(url, self.super_django_user, qs)
url = u'%s?user\u2605name=normal' % base_url
self.check_get_list(url, self.super_django_user, base_qs, expect=400)
+
+class LdapTest(BaseTest):
+
+ def use_test_setting(self, name, default=None):
+ setattr(settings, 'AUTH_LDAP_%s' % name,
+ getattr(settings, 'TEST_AUTH_LDAP_%s' % name, default))
+
+ def setUp(self):
+ super(LdapTest, self).setUp()
+ # Skip tests if basic LDAP test settings aren't defined.
+ if not getattr(settings, 'TEST_AUTH_LDAP_SERVER_URI', None):
+ self.skipTest('no test LDAP auth server defined')
+ self.ldap_username = getattr(settings, 'TEST_AUTH_LDAP_USERNAME', None)
+ if not self.ldap_username:
+ self.skipTest('no test LDAP username defined')
+ self.ldap_password = getattr(settings, 'TEST_AUTH_LDAP_PASSWORD', None)
+ if not self.ldap_password:
+ self.skipTest('no test LDAP password defined')
+ # Wrap settings so we can redfine them for each test.
+ self._wrapped = settings._wrapped
+ settings._wrapped = UserSettingsHolder(settings._wrapped)
+ # Reset all AUTH_LDAP_* settings to defaults.
+ for name, value in LDAPSettings.defaults.items():
+ setattr(settings, 'AUTH_LDAP_%s' % name, value)
+ # Set test LDAP settings that are always needed.
+ for name in ('SERVER_URI', 'BIND_DN', 'BIND_PASSWORD', 'USE_TLS'):
+ self.use_test_setting(name)
+
+ def tearDown(self):
+ super(LdapTest, self).tearDown()
+ settings._wrapped = self._wrapped
+
+ def check_login(self, username=None, password=None, should_fail=False):
+ username = username or self.ldap_username
+ password = password or self.ldap_password
+ result = self.client.login(username=username, password=password)
+ self.assertNotEqual(result, should_fail)
+ if not should_fail:
+ return User.objects.get(username=username)
+
+ def test_ldap_auth(self):
+ self.use_test_setting('USER_SEARCH')
+ self.assertEqual(User.objects.filter(username=self.ldap_username).count(), 0)
+ # Test logging in, user should be created with no flags or fields set.
+ user = self.check_login()
+ self.assertTrue(user.is_active)
+ self.assertFalse(user.has_usable_password())
+ self.assertFalse(user.is_superuser)
+ self.assertFalse(user.first_name)
+ self.assertFalse(user.last_name)
+ self.assertFalse(user.email)
+ # Test logging in with bad username or password.
+ self.check_login(username='not a valid user', should_fail=True)
+ self.check_login(password='not a valid pass', should_fail=True)
+ # Test using a flat DN instead of user search.
+ self.use_test_setting('USER_DN_TEMPLATE', None)
+ if settings.AUTH_LDAP_USER_DN_TEMPLATE:
+ user = self.check_login()
+ del settings.AUTH_LDAP_USER_DN_TEMPLATE
+ # Test user attributes assigned from LDAP.
+ self.use_test_setting('USER_ATTR_MAP', {})
+ if settings.AUTH_LDAP_USER_ATTR_MAP:
+ user = self.check_login()
+ for attr in settings.AUTH_LDAP_USER_ATTR_MAP.keys():
+ self.assertTrue(getattr(user, attr))
diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py
index 6f0b8320a7..15ce104881 100644
--- a/awx/settings/defaults.py
+++ b/awx/settings/defaults.py
@@ -165,6 +165,14 @@ REST_FRAMEWORK = {
),
}
+AUTHENTICATION_BACKENDS = (
+ 'awx.main.backend.LDAPBackend',
+ 'django.contrib.auth.backends.ModelBackend',
+)
+
+# LDAP server (default to None to skip using LDAP authentication).
+AUTH_LDAP_SERVER_URI = None
+
# Seconds before auth tokens expire.
AUTH_TOKEN_EXPIRATION = 1800
@@ -345,5 +353,8 @@ LOGGING = {
'handlers': ['null'],
'propagate': False,
},
+ 'django_auth_ldap': {
+ 'handlers': ['null'],
+ },
}
}
diff --git a/awx/settings/local_settings.py.example b/awx/settings/local_settings.py.example
index 17ed53e53b..9a4fabd889 100644
--- a/awx/settings/local_settings.py.example
+++ b/awx/settings/local_settings.py.example
@@ -60,6 +60,33 @@ SECRET_KEY = 'p7z7g1ql4%6+(6nlebb6hdk7sd^&fnjpal308%n%+p^_e6vo1y'
# reverse proxy.
REMOTE_HOST_HEADERS = ['REMOTE_ADDR', 'REMOTE_HOST']
+# LDAP connection and authentication settings. Refer to django-auth-ldap docs:
+# http://pythonhosted.org/django-auth-ldap/authentication.html
+AUTH_LDAP_SERVER_URI = ''
+AUTH_LDAP_BIND_DN = ''
+AUTH_LDAP_BIND_PASSWORD = ''
+AUTH_LDAP_START_TLS = False
+
+import ldap
+from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion
+
+# LDAP search query to find users.
+AUTH_LDAP_USER_SEARCH = LDAPSearch(
+ 'OU=Users,DC=example,DC=com',
+ ldap.SCOPE_SUBTREE,
+ '(sAMAccountName=%(user)s)',
+)
+
+# Alternative to user search.
+#AUTH_LDAP_USER_DN_TEMPLATE = 'sAMAccountName=%(user)s,OU=Users,DC=example,DC=com'
+
+# Mapping of LDAP attributes to user attributes.
+AUTH_LDAP_USER_ATTR_MAP = {
+ 'first_name': 'givenName',
+ 'last_name': 'sn',
+ 'email': 'mail',
+}
+
# Email address that error messages come from.
SERVER_EMAIL = 'root@localhost'
@@ -111,6 +138,10 @@ LOGGING['handlers']['syslog'] = {
#LOGGING['loggers']['awx.main.signals']['propagate'] = True
#LOGGING['loggers']['awx.main.permissions']['propagate'] = True
+# Enable the following lines to turn on LDAP auth logging.
+#LOGGING['loggers']['django_auth_ldap']['handlers'] = ['console']
+#LOGGING['loggers']['django_auth_ldap']['level'] = 'DEBUG'
+
# Define additional environment variables to be passed to subprocess started by
# the celery task.
#AWX_TASK_ENV['FOO'] = 'BAR'
@@ -141,3 +172,32 @@ TEST_SVN_USERNAME = ''
TEST_SVN_PASSWORD = ''
TEST_SVN_PUBLIC_HTTPS = 'https://projects.ninemoreminutes.com/svn/django-site-utils/trunk/'
TEST_SVN_PRIVATE_HTTPS = ''
+
+# LDAP connection and authentication settings for unit tests only. LDAP tests
+# will be skipped if not configured. Refer to django-auth-ldap docs:
+# http://pythonhosted.org/django-auth-ldap/authentication.html
+TEST_AUTH_LDAP_SERVER_URI = ''
+TEST_AUTH_LDAP_BIND_DN = ''
+TEST_AUTH_LDAP_BIND_PASSWORD = ''
+TEST_AUTH_LDAP_START_TLS = False
+
+# LDAP username/password for testing authentication.
+TEST_AUTH_LDAP_USERNAME = ''
+TEST_AUTH_LDAP_PASSWORD = ''
+
+# LDAP search query to find users.
+TEST_AUTH_LDAP_USER_SEARCH = LDAPSearch(
+ 'OU=Users,DC=example,DC=com',
+ ldap.SCOPE_SUBTREE,
+ '(sAMAccountName=%(user)s)',
+)
+
+# Alternative to user search.
+TEST_AUTH_LDAP_USER_DN_TEMPLATE = 'sAMAccountName=%(user)s,OU=Users,DC=example,DC=com'
+
+# Mapping of LDAP attributes to user attributes.
+TEST_AUTH_LDAP_USER_ATTR_MAP = {
+ 'first_name': 'givenName',
+ 'last_name': 'sn',
+ 'email': 'mail',
+}
diff --git a/config/deb/settings.py b/config/deb/settings.py
index 50ac050710..015d074de3 100644
--- a/config/deb/settings.py
+++ b/config/deb/settings.py
@@ -54,3 +54,31 @@ EMAIL_PORT = 25
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
EMAIL_USE_TLS = False
+
+# LDAP connection and authentication settings. Refer to django-auth-ldap docs:
+# http://pythonhosted.org/django-auth-ldap/authentication.html
+
+AUTH_LDAP_SERVER_URI = ''
+AUTH_LDAP_BIND_DN = ''
+AUTH_LDAP_BIND_PASSWORD = ''
+AUTH_LDAP_START_TLS = False
+
+#import ldap
+#from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion
+
+# LDAP search query to find users.
+#AUTH_LDAP_USER_SEARCH = LDAPSearch(
+# 'OU=Users,DC=example,DC=com',
+# ldap.SCOPE_SUBTREE,
+# '(sAMAccountName=%(user)s)',
+#)
+
+# Alternative to user search.
+#AUTH_LDAP_USER_DN_TEMPLATE = 'sAMAccountName=%(user)s,OU=Users,DC=example,DC=com'
+
+# Mapping of LDAP attributes to user attributes.
+#AUTH_LDAP_USER_ATTR_MAP = {
+# 'first_name': 'givenName',
+# 'last_name': 'sn',
+# 'email': 'mail',
+#}
diff --git a/config/rpm/settings.py b/config/rpm/settings.py
index 50ac050710..015d074de3 100644
--- a/config/rpm/settings.py
+++ b/config/rpm/settings.py
@@ -54,3 +54,31 @@ EMAIL_PORT = 25
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
EMAIL_USE_TLS = False
+
+# LDAP connection and authentication settings. Refer to django-auth-ldap docs:
+# http://pythonhosted.org/django-auth-ldap/authentication.html
+
+AUTH_LDAP_SERVER_URI = ''
+AUTH_LDAP_BIND_DN = ''
+AUTH_LDAP_BIND_PASSWORD = ''
+AUTH_LDAP_START_TLS = False
+
+#import ldap
+#from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion
+
+# LDAP search query to find users.
+#AUTH_LDAP_USER_SEARCH = LDAPSearch(
+# 'OU=Users,DC=example,DC=com',
+# ldap.SCOPE_SUBTREE,
+# '(sAMAccountName=%(user)s)',
+#)
+
+# Alternative to user search.
+#AUTH_LDAP_USER_DN_TEMPLATE = 'sAMAccountName=%(user)s,OU=Users,DC=example,DC=com'
+
+# Mapping of LDAP attributes to user attributes.
+#AUTH_LDAP_USER_ATTR_MAP = {
+# 'first_name': 'givenName',
+# 'last_name': 'sn',
+# 'email': 'mail',
+#}