mirror of
https://github.com/ArchiveBox/ArchiveBox.git
synced 2026-04-06 07:47:53 +10:00
219 lines
8.3 KiB
Python
219 lines
8.3 KiB
Python
"""
|
|
LDAP authentication tests for ArchiveBox.
|
|
|
|
Tests LDAP configuration, validation, and integration with Django.
|
|
Per CLAUDE.md: NO MOCKS, NO SKIPS - all tests use real code paths.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from importlib.util import find_spec
|
|
|
|
|
|
class TestLDAPConfig(unittest.TestCase):
|
|
"""Test LDAP configuration loading and validation."""
|
|
|
|
def test_ldap_config_defaults(self):
|
|
"""Test that LDAP config loads with correct defaults."""
|
|
from archivebox.config.ldap import LDAP_CONFIG
|
|
|
|
# Check default values
|
|
self.assertFalse(LDAP_CONFIG.LDAP_ENABLED)
|
|
self.assertIsNone(LDAP_CONFIG.LDAP_SERVER_URI)
|
|
self.assertIsNone(LDAP_CONFIG.LDAP_BIND_DN)
|
|
self.assertIsNone(LDAP_CONFIG.LDAP_BIND_PASSWORD)
|
|
self.assertIsNone(LDAP_CONFIG.LDAP_USER_BASE)
|
|
self.assertEqual(LDAP_CONFIG.LDAP_USER_FILTER, "(uid=%(user)s)")
|
|
self.assertEqual(LDAP_CONFIG.LDAP_USERNAME_ATTR, "username")
|
|
self.assertEqual(LDAP_CONFIG.LDAP_FIRSTNAME_ATTR, "givenName")
|
|
self.assertEqual(LDAP_CONFIG.LDAP_LASTNAME_ATTR, "sn")
|
|
self.assertEqual(LDAP_CONFIG.LDAP_EMAIL_ATTR, "mail")
|
|
self.assertFalse(LDAP_CONFIG.LDAP_CREATE_SUPERUSER)
|
|
|
|
def test_ldap_config_validation_disabled(self):
|
|
"""Test that validation passes when LDAP is disabled."""
|
|
from archivebox.config.ldap import LDAPConfig
|
|
|
|
config = LDAPConfig(LDAP_ENABLED=False)
|
|
is_valid, error_msg = config.validate_ldap_config()
|
|
|
|
self.assertTrue(is_valid)
|
|
self.assertEqual(error_msg, "")
|
|
|
|
def test_ldap_config_validation_missing_fields(self):
|
|
"""Test that validation fails when required fields are missing."""
|
|
from archivebox.config.ldap import LDAPConfig
|
|
|
|
# Enable LDAP but don't provide required fields
|
|
config = LDAPConfig(LDAP_ENABLED=True)
|
|
is_valid, error_msg = config.validate_ldap_config()
|
|
|
|
self.assertFalse(is_valid)
|
|
self.assertIn("LDAP_* config options must all be set", error_msg)
|
|
self.assertIn("LDAP_SERVER_URI", error_msg)
|
|
self.assertIn("LDAP_BIND_DN", error_msg)
|
|
self.assertIn("LDAP_BIND_PASSWORD", error_msg)
|
|
self.assertIn("LDAP_USER_BASE", error_msg)
|
|
|
|
def test_ldap_config_validation_complete(self):
|
|
"""Test that validation passes when all required fields are provided."""
|
|
from archivebox.config.ldap import LDAPConfig
|
|
|
|
config = LDAPConfig(
|
|
LDAP_ENABLED=True,
|
|
LDAP_SERVER_URI="ldap://ldap-test.localhost:389",
|
|
LDAP_BIND_DN="cn=admin,dc=example,dc=com",
|
|
LDAP_BIND_PASSWORD="password",
|
|
LDAP_USER_BASE="ou=users,dc=example,dc=com",
|
|
)
|
|
is_valid, error_msg = config.validate_ldap_config()
|
|
|
|
self.assertTrue(is_valid)
|
|
self.assertEqual(error_msg, "")
|
|
|
|
def test_ldap_config_in_get_config(self):
|
|
"""Test that LDAP_CONFIG is included in get_CONFIG()."""
|
|
from archivebox.config import get_CONFIG
|
|
|
|
all_config = get_CONFIG()
|
|
self.assertIn("LDAP_CONFIG", all_config)
|
|
self.assertEqual(all_config["LDAP_CONFIG"].__class__.__name__, "LDAPConfig")
|
|
|
|
|
|
class TestLDAPIntegration(unittest.TestCase):
|
|
"""Test LDAP integration with Django settings."""
|
|
|
|
def test_django_settings_without_ldap_enabled(self):
|
|
"""Test that Django settings work correctly when LDAP is disabled."""
|
|
# Import Django settings (LDAP_ENABLED should be False by default)
|
|
from django.conf import settings
|
|
|
|
# Should have default authentication backends
|
|
self.assertIn("django.contrib.auth.backends.RemoteUserBackend", settings.AUTHENTICATION_BACKENDS)
|
|
self.assertIn("django.contrib.auth.backends.ModelBackend", settings.AUTHENTICATION_BACKENDS)
|
|
|
|
# LDAP backend should not be present when disabled
|
|
ldap_backends = [b for b in settings.AUTHENTICATION_BACKENDS if "ldap" in b.lower()]
|
|
self.assertEqual(len(ldap_backends), 0, "LDAP backend should not be present when LDAP_ENABLED=False")
|
|
|
|
def test_django_settings_with_ldap_library_check(self):
|
|
"""Test that Django settings check for LDAP libraries when enabled."""
|
|
ldap_available = find_spec("django_auth_ldap") is not None and find_spec("ldap") is not None
|
|
|
|
# If LDAP libraries are not available, settings should handle gracefully
|
|
if not ldap_available:
|
|
# Settings should have loaded without LDAP backend
|
|
from django.conf import settings
|
|
|
|
ldap_backends = [b for b in settings.AUTHENTICATION_BACKENDS if "ldap" in b.lower()]
|
|
self.assertEqual(len(ldap_backends), 0, "LDAP backend should not be present when libraries unavailable")
|
|
|
|
|
|
class TestLDAPAuthBackend(unittest.TestCase):
|
|
"""Test custom LDAP authentication backend."""
|
|
|
|
def test_ldap_backend_class_exists(self):
|
|
"""Test that ArchiveBoxLDAPBackend class is defined."""
|
|
from archivebox.ldap.auth import ArchiveBoxLDAPBackend
|
|
|
|
self.assertTrue(hasattr(ArchiveBoxLDAPBackend, "authenticate_ldap_user"))
|
|
|
|
def test_ldap_backend_inherits_correctly(self):
|
|
"""Test that ArchiveBoxLDAPBackend has correct inheritance."""
|
|
from archivebox.ldap.auth import ArchiveBoxLDAPBackend
|
|
|
|
# Should have authenticate_ldap_user method (from base or overridden)
|
|
self.assertTrue(callable(getattr(ArchiveBoxLDAPBackend, "authenticate_ldap_user", None)))
|
|
|
|
|
|
class TestArchiveBoxWithLDAP(unittest.TestCase):
|
|
"""Test ArchiveBox commands with LDAP configuration."""
|
|
|
|
def setUp(self):
|
|
"""Set up test environment."""
|
|
self.work_dir = tempfile.mkdtemp(prefix="archivebox-ldap-test-")
|
|
|
|
def test_archivebox_init_without_ldap(self):
|
|
"""Test that archivebox init works without LDAP enabled."""
|
|
import subprocess
|
|
|
|
# Run archivebox init
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "archivebox", "init"],
|
|
cwd=self.work_dir,
|
|
capture_output=True,
|
|
timeout=45,
|
|
env={
|
|
**os.environ,
|
|
"DATA_DIR": self.work_dir,
|
|
"LDAP_ENABLED": "False",
|
|
},
|
|
)
|
|
|
|
# Should succeed
|
|
self.assertEqual(result.returncode, 0, f"archivebox init failed: {result.stderr.decode()}")
|
|
|
|
def test_archivebox_version_with_ldap_config(self):
|
|
"""Test that archivebox version works with LDAP config set."""
|
|
import subprocess
|
|
|
|
# Run archivebox version with LDAP config env vars
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "archivebox", "version"],
|
|
cwd=self.work_dir,
|
|
capture_output=True,
|
|
timeout=10,
|
|
env={
|
|
**os.environ,
|
|
"DATA_DIR": self.work_dir,
|
|
"LDAP_ENABLED": "False",
|
|
"LDAP_SERVER_URI": "ldap://ldap-test.localhost:389",
|
|
},
|
|
)
|
|
|
|
# Should succeed
|
|
self.assertEqual(result.returncode, 0, f"archivebox version failed: {result.stderr.decode()}")
|
|
|
|
|
|
class TestLDAPConfigValidationInArchiveBox(unittest.TestCase):
|
|
"""Test LDAP config validation when running ArchiveBox commands."""
|
|
|
|
def setUp(self):
|
|
"""Set up test environment."""
|
|
self.work_dir = tempfile.mkdtemp(prefix="archivebox-ldap-validation-")
|
|
|
|
def test_archivebox_init_with_incomplete_ldap_config(self):
|
|
"""Test that archivebox init fails with helpful error when LDAP config is incomplete."""
|
|
import subprocess
|
|
|
|
# Run archivebox init with LDAP enabled but missing required fields
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "archivebox", "init"],
|
|
cwd=self.work_dir,
|
|
capture_output=True,
|
|
timeout=45,
|
|
env={
|
|
**os.environ,
|
|
"DATA_DIR": self.work_dir,
|
|
"LDAP_ENABLED": "True",
|
|
# Missing: LDAP_SERVER_URI, LDAP_BIND_DN, etc.
|
|
},
|
|
)
|
|
|
|
# Should fail with validation error
|
|
self.assertNotEqual(result.returncode, 0, "Should fail with incomplete LDAP config")
|
|
|
|
# Check error message
|
|
stderr = result.stderr.decode()
|
|
self.assertIn(
|
|
"LDAP_* config options must all be set",
|
|
stderr,
|
|
f"Expected validation error message in: {stderr}",
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|