forked from Github-Mirrors/canaille
feat: ldap connection is lazilly opened
This commit is contained in:
parent
d0dbaa588c
commit
5c11ebf0d3
3 changed files with 52 additions and 85 deletions
|
@ -44,14 +44,12 @@ class BaseBackend:
|
||||||
This method will be called before each http request,
|
This method will be called before each http request,
|
||||||
it should open the connection to the backend.
|
it should open the connection to the backend.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def teardown(self):
|
def teardown(self):
|
||||||
"""
|
"""
|
||||||
This method will be called after each http request,
|
This method will be called after each http request,
|
||||||
it should close the connections to the backend.
|
it should close the connections to the backend.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate(cls, config):
|
def validate(cls, config):
|
||||||
|
|
|
@ -10,7 +10,6 @@ from canaille.app.configuration import ConfigurationException
|
||||||
from canaille.app.i18n import gettext as _
|
from canaille.app.i18n import gettext as _
|
||||||
from canaille.backends import BaseBackend
|
from canaille.backends import BaseBackend
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from flask import request
|
|
||||||
|
|
||||||
from .utils import listify
|
from .utils import listify
|
||||||
|
|
||||||
|
@ -51,7 +50,7 @@ def install_schema(config, schema_path):
|
||||||
class Backend(BaseBackend):
|
class Backend(BaseBackend):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
super().__init__(config)
|
super().__init__(config)
|
||||||
self.connection = None
|
self._connection = None
|
||||||
setup_ldap_models(config)
|
setup_ldap_models(config)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -74,23 +73,18 @@ class Backend(BaseBackend):
|
||||||
os.path.dirname(__file__) + "/schemas/oauth2-openldap.ldif",
|
os.path.dirname(__file__) + "/schemas/oauth2-openldap.ldif",
|
||||||
)
|
)
|
||||||
|
|
||||||
def setup(self):
|
@property
|
||||||
if self.connection:
|
def connection(self):
|
||||||
return
|
if self._connection:
|
||||||
|
return self._connection
|
||||||
try: # pragma: no cover
|
|
||||||
if request.endpoint == "static":
|
|
||||||
return
|
|
||||||
except RuntimeError: # pragma: no cover
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.connection = ldap.initialize(self.config["BACKENDS"]["LDAP"]["URI"])
|
self._connection = ldap.initialize(self.config["BACKENDS"]["LDAP"]["URI"])
|
||||||
self.connection.set_option(
|
self._connection.set_option(
|
||||||
ldap.OPT_NETWORK_TIMEOUT,
|
ldap.OPT_NETWORK_TIMEOUT,
|
||||||
self.config["BACKENDS"]["LDAP"].get("TIMEOUT"),
|
self.config["BACKENDS"]["LDAP"].get("TIMEOUT"),
|
||||||
)
|
)
|
||||||
self.connection.simple_bind_s(
|
self._connection.simple_bind_s(
|
||||||
self.config["BACKENDS"]["LDAP"]["BIND_DN"],
|
self.config["BACKENDS"]["LDAP"]["BIND_DN"],
|
||||||
self.config["BACKENDS"]["LDAP"]["BIND_PW"],
|
self.config["BACKENDS"]["LDAP"]["BIND_PW"],
|
||||||
)
|
)
|
||||||
|
@ -109,82 +103,62 @@ class Backend(BaseBackend):
|
||||||
logging.error(message)
|
logging.error(message)
|
||||||
raise ConfigurationException(message) from exc
|
raise ConfigurationException(message) from exc
|
||||||
|
|
||||||
def teardown(self):
|
return self._connection
|
||||||
try: # pragma: no cover
|
|
||||||
if request.endpoint == "static":
|
|
||||||
return
|
|
||||||
except RuntimeError: # pragma: no cover
|
|
||||||
pass
|
|
||||||
|
|
||||||
if self.connection: # pragma: no branch
|
def teardown(self):
|
||||||
self.connection.unbind_s()
|
if self._connection: # pragma: no branch
|
||||||
self.connection = None
|
self._connection.unbind_s()
|
||||||
|
self._connection = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate(cls, config):
|
def validate(cls, config):
|
||||||
from canaille.app import models
|
from canaille.app import models
|
||||||
|
|
||||||
backend = cls(config)
|
with cls(config).session():
|
||||||
try:
|
try:
|
||||||
backend.setup()
|
user = models.User(
|
||||||
models.User.ldap_object_classes()
|
formatted_name=f"canaille_{uuid.uuid4()}",
|
||||||
|
family_name=f"canaille_{uuid.uuid4()}",
|
||||||
|
user_name=f"canaille_{uuid.uuid4()}",
|
||||||
|
emails=f"canaille_{uuid.uuid4()}@mydomain.tld",
|
||||||
|
password="correct horse battery staple",
|
||||||
|
)
|
||||||
|
user.save()
|
||||||
|
user.delete()
|
||||||
|
|
||||||
except ldap.SERVER_DOWN as exc:
|
except ldap.INSUFFICIENT_ACCESS as exc:
|
||||||
raise ConfigurationException(
|
raise ConfigurationException(
|
||||||
f'Could not connect to the LDAP server \'{config["BACKENDS"]["LDAP"]["URI"]}\''
|
f'LDAP user \'{config["BACKENDS"]["LDAP"]["BIND_DN"]}\' cannot create '
|
||||||
) from exc
|
f'users at \'{config["BACKENDS"]["LDAP"]["USER_BASE"]}\''
|
||||||
|
) from exc
|
||||||
|
|
||||||
except ldap.INVALID_CREDENTIALS as exc:
|
try:
|
||||||
raise ConfigurationException(
|
models.Group.ldap_object_classes()
|
||||||
f'LDAP authentication failed with user \'{config["BACKENDS"]["LDAP"]["BIND_DN"]}\''
|
|
||||||
) from exc
|
|
||||||
|
|
||||||
try:
|
user = models.User(
|
||||||
user = models.User(
|
cn=f"canaille_{uuid.uuid4()}",
|
||||||
formatted_name=f"canaille_{uuid.uuid4()}",
|
family_name=f"canaille_{uuid.uuid4()}",
|
||||||
family_name=f"canaille_{uuid.uuid4()}",
|
user_name=f"canaille_{uuid.uuid4()}",
|
||||||
user_name=f"canaille_{uuid.uuid4()}",
|
emails=f"canaille_{uuid.uuid4()}@mydomain.tld",
|
||||||
emails=f"canaille_{uuid.uuid4()}@mydomain.tld",
|
password="correct horse battery staple",
|
||||||
password="correct horse battery staple",
|
)
|
||||||
)
|
user.save()
|
||||||
user.save()
|
|
||||||
user.delete()
|
|
||||||
|
|
||||||
except ldap.INSUFFICIENT_ACCESS as exc:
|
group = models.Group(
|
||||||
raise ConfigurationException(
|
display_name=f"canaille_{uuid.uuid4()}",
|
||||||
f'LDAP user \'{config["BACKENDS"]["LDAP"]["BIND_DN"]}\' cannot create '
|
members=[user],
|
||||||
f'users at \'{config["BACKENDS"]["LDAP"]["USER_BASE"]}\''
|
)
|
||||||
) from exc
|
group.save()
|
||||||
|
group.delete()
|
||||||
|
|
||||||
try:
|
except ldap.INSUFFICIENT_ACCESS as exc:
|
||||||
models.Group.ldap_object_classes()
|
raise ConfigurationException(
|
||||||
|
f'LDAP user \'{config["BACKENDS"]["LDAP"]["BIND_DN"]}\' cannot create '
|
||||||
|
f'groups at \'{config["BACKENDS"]["LDAP"]["GROUP_BASE"]}\''
|
||||||
|
) from exc
|
||||||
|
|
||||||
user = models.User(
|
finally:
|
||||||
cn=f"canaille_{uuid.uuid4()}",
|
user.delete()
|
||||||
family_name=f"canaille_{uuid.uuid4()}",
|
|
||||||
user_name=f"canaille_{uuid.uuid4()}",
|
|
||||||
emails=f"canaille_{uuid.uuid4()}@mydomain.tld",
|
|
||||||
password="correct horse battery staple",
|
|
||||||
)
|
|
||||||
user.save()
|
|
||||||
|
|
||||||
group = models.Group(
|
|
||||||
display_name=f"canaille_{uuid.uuid4()}",
|
|
||||||
members=[user],
|
|
||||||
)
|
|
||||||
group.save()
|
|
||||||
group.delete()
|
|
||||||
|
|
||||||
except ldap.INSUFFICIENT_ACCESS as exc:
|
|
||||||
raise ConfigurationException(
|
|
||||||
f'LDAP user \'{config["BACKENDS"]["LDAP"]["BIND_DN"]}\' cannot create '
|
|
||||||
f'groups at \'{config["BACKENDS"]["LDAP"]["GROUP_BASE"]}\''
|
|
||||||
) from exc
|
|
||||||
|
|
||||||
finally:
|
|
||||||
user.delete()
|
|
||||||
|
|
||||||
backend.teardown()
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def login_placeholder(cls):
|
def login_placeholder(cls):
|
||||||
|
|
|
@ -10,11 +10,6 @@ def test_required_methods(testclient):
|
||||||
BaseBackend.validate({})
|
BaseBackend.validate({})
|
||||||
|
|
||||||
backend = BaseBackend(testclient.app.config)
|
backend = BaseBackend(testclient.app.config)
|
||||||
with pytest.raises(NotImplementedError):
|
|
||||||
backend.setup()
|
|
||||||
|
|
||||||
with pytest.raises(NotImplementedError):
|
|
||||||
backend.teardown()
|
|
||||||
|
|
||||||
with pytest.raises(NotImplementedError):
|
with pytest.raises(NotImplementedError):
|
||||||
backend.has_account_lockability()
|
backend.has_account_lockability()
|
||||||
|
|
Loading…
Reference in a new issue