mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Increase LDAP coverage.
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from modoboa.core.models import User
|
||||
from modoboa.core import tests as core_tests
|
||||
from modoboa.lib import parameters
|
||||
from modoboa.lib.tests import ModoTestCase
|
||||
|
||||
from .. import factories
|
||||
@@ -152,6 +154,22 @@ class AccountTestCase(ModoTestCase):
|
||||
)
|
||||
|
||||
|
||||
class LDAPAccountTestCase(core_tests.LDAPTestCaseMixin, ModoTestCase):
|
||||
"""Check LDAP related code."""
|
||||
|
||||
def test_autocreate_disabled(self):
|
||||
"""Check if objects are not created as expected."""
|
||||
self.activate_ldap_authentication()
|
||||
self.searchbind_mode()
|
||||
parameters.save_admin("AUTO_CREATE_DOMAIN_AND_MAILBOX", "no")
|
||||
username = "testuser@example.com"
|
||||
self.authenticate(username, "test")
|
||||
self.assertFalse(
|
||||
models.Domain.objects.filter(name="example.com").exists())
|
||||
self.assertFalse(
|
||||
models.Mailbox.objects.filter(address="testuser").exists())
|
||||
|
||||
|
||||
class PermissionsTestCase(ModoTestCase):
|
||||
|
||||
@classmethod
|
||||
|
||||
+75
-18
@@ -3,6 +3,7 @@
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import override_settings
|
||||
|
||||
from modoboa.lib import exceptions
|
||||
from modoboa.lib import parameters
|
||||
from modoboa.lib.tests import ModoTestCase
|
||||
|
||||
@@ -39,20 +40,65 @@ class AuthenticationTestCase(ModoTestCase):
|
||||
self.assertTrue(response.url.endswith(reverse("admin:domain_list")))
|
||||
|
||||
|
||||
class LDAPTestCaseMixin(object):
|
||||
"""Set of methods used to test LDAP features."""
|
||||
|
||||
def activate_ldap_authentication(self):
|
||||
"""Modify settings."""
|
||||
parameters.save_admin(
|
||||
"AUTHENTICATION_TYPE", "ldap")
|
||||
parameters.save_admin("LDAP_SERVER_PORT", "3389")
|
||||
|
||||
def restore_user_password(self, username, new_password):
|
||||
"""Restore user password to its initial state."""
|
||||
from modoboa.lib.ldap_utils import LDAPAuthBackend
|
||||
|
||||
backend = LDAPAuthBackend()
|
||||
for password in ["Toto1234", "test"]:
|
||||
try:
|
||||
backend.update_user_password(
|
||||
username, password, new_password)
|
||||
except exceptions.InternalError as exp:
|
||||
print exp
|
||||
pass
|
||||
else:
|
||||
return
|
||||
raise RuntimeError("Can't restore user password.")
|
||||
|
||||
def authenticate(self, user, password, restore_before=True):
|
||||
"""Restore password and authenticate user."""
|
||||
self.client.logout()
|
||||
if restore_before:
|
||||
self.restore_user_password(user, password)
|
||||
self.assertTrue(
|
||||
self.client.login(username=user, password=password))
|
||||
|
||||
def searchbind_mode(self):
|
||||
"""Apply settings required by the searchbind mode."""
|
||||
parameters.save_admin("LDAP_AUTH_METHOD", "searchbind")
|
||||
parameters.save_admin("LDAP_BIND_DN", "cn=admin,dc=example,dc=com")
|
||||
parameters.save_admin("LDAP_BIND_PASSWORD", "test")
|
||||
parameters.save_admin("LDAP_SEARCH_BASE", "ou=users,dc=example,dc=com")
|
||||
|
||||
def directbind_mode(self):
|
||||
"""Apply settings required by the directbind mode."""
|
||||
parameters.save_admin("LDAP_AUTH_METHOD", "directbind")
|
||||
parameters.save_admin(
|
||||
"LDAP_USER_DN_TEMPLATE", "cn=%(user)s,ou=users,dc=example,dc=com")
|
||||
|
||||
|
||||
@override_settings(AUTHENTICATION_BACKENDS=(
|
||||
'modoboa.lib.authbackends.LDAPBackend',
|
||||
'modoboa.lib.authbackends.SimpleBackend',
|
||||
))
|
||||
class LDAPAuthenticationTestCase(ModoTestCase):
|
||||
class LDAPAuthenticationTestCase(LDAPTestCaseMixin, ModoTestCase):
|
||||
|
||||
"""Validate LDAP authentication scenarios."""
|
||||
|
||||
def setUp(self):
|
||||
"""Create test data."""
|
||||
super(LDAPAuthenticationTestCase, self).setUp()
|
||||
parameters.save_admin(
|
||||
"AUTHENTICATION_TYPE", "ldap")
|
||||
parameters.save_admin("LDAP_SERVER_PORT", "3389")
|
||||
self.activate_ldap_authentication()
|
||||
|
||||
def check_created_user(self, username, group="SimpleUsers", with_mb=True):
|
||||
"""Check that created user is valid."""
|
||||
@@ -66,13 +112,9 @@ class LDAPAuthenticationTestCase(ModoTestCase):
|
||||
@override_settings(AUTH_LDAP_USER_DN_TEMPLATE=None)
|
||||
def test_searchbind_authentication(self):
|
||||
"""Test the bind&search method."""
|
||||
self.client.logout()
|
||||
parameters.save_admin("LDAP_AUTH_METHOD", "searchbind")
|
||||
parameters.save_admin("LDAP_BIND_DN", "cn=admin,dc=example,dc=com")
|
||||
parameters.save_admin("LDAP_BIND_PASSWORD", "test")
|
||||
parameters.save_admin("LDAP_SEARCH_BASE", "ou=users,dc=example,dc=com")
|
||||
self.searchbind_mode()
|
||||
username = "testuser@example.com"
|
||||
self.assertTrue(self.client.login(username=username, password="test"))
|
||||
self.authenticate(username, "test")
|
||||
self.check_created_user(username)
|
||||
self.client.logout()
|
||||
|
||||
@@ -80,22 +122,19 @@ class LDAPAuthenticationTestCase(ModoTestCase):
|
||||
parameters.save_admin(
|
||||
"LDAP_GROUPS_SEARCH_BASE", "ou=groups,dc=example,dc=com")
|
||||
username = "mailadmin@example.com"
|
||||
self.assertTrue(self.client.login(username=username, password="test"))
|
||||
self.authenticate(username, "test", False)
|
||||
self.check_created_user(username, "DomainAdmins")
|
||||
|
||||
def test_directbind_authentication(self):
|
||||
"""Test the directbind method."""
|
||||
self.client.logout()
|
||||
parameters.save_admin("LDAP_AUTH_METHOD", "directbind")
|
||||
parameters.save_admin(
|
||||
"LDAP_USER_DN_TEMPLATE", "cn=%(user)s,ou=users,dc=example,dc=com")
|
||||
self.directbind_mode()
|
||||
|
||||
# 1: must fail because usernames of simple users must be email
|
||||
# addresses
|
||||
username = "testuser"
|
||||
with self.assertRaises(TypeError):
|
||||
self.assertTrue(self.client.login(
|
||||
username=username, password="test"))
|
||||
self.client.login(username=username, password="test")
|
||||
|
||||
# 1: must work because usernames of domain admins are not
|
||||
# always email addresses
|
||||
@@ -103,11 +142,11 @@ class LDAPAuthenticationTestCase(ModoTestCase):
|
||||
parameters.save_admin(
|
||||
"LDAP_GROUPS_SEARCH_BASE", "ou=groups,dc=example,dc=com")
|
||||
username = "mailadmin"
|
||||
self.assertTrue(self.client.login(username=username, password="test"))
|
||||
self.authenticate(username, "test", False)
|
||||
self.check_created_user(username, "DomainAdmins", False)
|
||||
|
||||
|
||||
class ProfileTestCase(ModoTestCase):
|
||||
class ProfileTestCase(LDAPTestCaseMixin, ModoTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
@@ -153,6 +192,24 @@ class ProfileTestCase(ModoTestCase):
|
||||
self.client.login(username="user@test.com", password="Toto1234")
|
||||
)
|
||||
|
||||
@override_settings(AUTHENTICATION_BACKENDS=(
|
||||
'modoboa.lib.authbackends.LDAPBackend',
|
||||
'modoboa.lib.authbackends.SimpleBackend',
|
||||
))
|
||||
def test_update_password_ldap(self):
|
||||
"""Update password for an LDAP user."""
|
||||
self.activate_ldap_authentication()
|
||||
self.searchbind_mode()
|
||||
|
||||
username = "testuser@example.com"
|
||||
self.authenticate(username, "test")
|
||||
self.ajax_post(
|
||||
reverse("core:user_profile"),
|
||||
{"language": "en", "oldpassword": "test",
|
||||
"newpassword": "Toto1234", "confirmation": "Toto1234"}
|
||||
)
|
||||
self.authenticate(username, "Toto1234", False)
|
||||
|
||||
|
||||
class APIAccessFormTestCase(ModoTestCase):
|
||||
|
||||
|
||||
+21
-13
@@ -46,6 +46,7 @@ from modoboa.lib.exceptions import InternalError
|
||||
class LDAPAuthBackend(object):
|
||||
|
||||
def __init__(self):
|
||||
parameters.apply_to_django_settings()
|
||||
self.server_uri = self._setting(
|
||||
"AUTH_LDAP_SERVER_URI", "ldap://localhost"
|
||||
)
|
||||
@@ -53,7 +54,6 @@ class LDAPAuthBackend(object):
|
||||
self.ldap_ad = self._setting("LDAP_ACTIVE_DIRECTORY", False)
|
||||
self.conn = None
|
||||
self.user_filter = self._setting("LDAP_USER_FILTER", "")
|
||||
self.user_dn = None
|
||||
|
||||
def _setting(self, name, default):
|
||||
try:
|
||||
@@ -63,6 +63,7 @@ class LDAPAuthBackend(object):
|
||||
return value
|
||||
|
||||
def _get_conn(self, dn, password):
|
||||
"""Get a connection from the server."""
|
||||
conn = ldap.initialize(self.server_uri)
|
||||
conn.set_option(ldap.OPT_X_TLS_DEMAND, True)
|
||||
conn.set_option(ldap.OPT_DEBUG_LEVEL, 255)
|
||||
@@ -70,17 +71,21 @@ class LDAPAuthBackend(object):
|
||||
return conn
|
||||
|
||||
def connect_to_server(self, user, password):
|
||||
if parameters.get_admin("LDAP_AUTH_METHOD", app="core") == "searchbind":
|
||||
"""Connect to the server according to configuration."""
|
||||
if self.conn is not None:
|
||||
return
|
||||
mode = parameters.get_admin("LDAP_AUTH_METHOD", app="core")
|
||||
if mode == "searchbind":
|
||||
bind_dn = self._setting("AUTH_LDAP_BIND_DN", "")
|
||||
bind_pwd = self._setting("AUTH_LDAP_BIND_PASSWORD", "")
|
||||
self.conn = self._get_conn(bind_dn, bind_pwd)
|
||||
self.user_dn = self._find_user_dn(user)
|
||||
else:
|
||||
tpl = self._setting("AUTH_LDAP_USER_DN_TEMPLATE", "")
|
||||
self.user_dn = tpl % {"user": user}
|
||||
self.conn = self._get_conn(self.user_dn, password)
|
||||
|
||||
def _find_user_dn(self, user):
|
||||
"""Find the DN of the given user."""
|
||||
sbase = parameters.get_admin("LDAP_SEARCH_BASE", app="core")
|
||||
sfilter = parameters.get_admin("LDAP_SEARCH_FILTER", app="core")
|
||||
sfilter = sfilter % {"user": user}
|
||||
@@ -102,15 +107,18 @@ class LDAPAuthBackend(object):
|
||||
return hasher.encrypt(clearpassword)
|
||||
|
||||
def update_user_password(self, user, password, newpassword):
|
||||
"""Update user password."""
|
||||
self.connect_to_server(user, password)
|
||||
user_dn = self._find_user_dn(user)
|
||||
if self.ldap_ad:
|
||||
newpassword = (
|
||||
('"%s"' % newpassword).encode('utf-16').lstrip('\377\376')
|
||||
)
|
||||
ldif = [(ldap.MOD_REPLACE,
|
||||
self.pwd_attr,
|
||||
self._crypt_password(newpassword))]
|
||||
try:
|
||||
self.connect_to_server(user, password)
|
||||
if self.ldap_ad:
|
||||
newpassword = (
|
||||
('"%s"' % newpassword).encode('utf-16').lstrip('\377\376')
|
||||
)
|
||||
ldif = [(ldap.MOD_REPLACE,
|
||||
self.pwd_attr,
|
||||
self._crypt_password(newpassword))]
|
||||
self.conn.modify_s(self.user_dn, ldif)
|
||||
self.conn.modify_s(user_dn, ldif)
|
||||
except ldap.LDAPError as e:
|
||||
raise InternalError(_("Failed to update password: %s" % str(e)))
|
||||
raise InternalError(
|
||||
_("Failed to update password: {}").format(e))
|
||||
|
||||
Reference in New Issue
Block a user