sources/ldap: allow multiple server URIs for loadbalancing and failover
closes #1874 Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
7e316b5fc2
commit
75051687e6
|
@ -68,9 +68,9 @@ class DomainlessURLValidator(URLValidator):
|
||||||
)
|
)
|
||||||
self.schemes = ["http", "https", "blank"] + list(self.schemes)
|
self.schemes = ["http", "https", "blank"] + list(self.schemes)
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value: str):
|
||||||
# Check if the scheme is valid.
|
# Check if the scheme is valid.
|
||||||
scheme = value.split("://")[0].lower()
|
scheme = value.split("://")[0].lower()
|
||||||
if scheme not in self.schemes:
|
if scheme not in self.schemes:
|
||||||
value = "default" + value
|
value = "default" + value
|
||||||
return super().__call__(value)
|
super().__call__(value)
|
||||||
|
|
|
@ -3,7 +3,7 @@ from typing import Optional, Type
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from ldap3 import ALL, Connection, Server
|
from ldap3 import ALL, ROUND_ROBIN, Connection, Server, ServerPool
|
||||||
from rest_framework.serializers import Serializer
|
from rest_framework.serializers import Serializer
|
||||||
|
|
||||||
from authentik.core.models import Group, PropertyMapping, Source
|
from authentik.core.models import Group, PropertyMapping, Source
|
||||||
|
@ -12,11 +12,22 @@ from authentik.lib.models import DomainlessURLValidator
|
||||||
LDAP_TIMEOUT = 15
|
LDAP_TIMEOUT = 15
|
||||||
|
|
||||||
|
|
||||||
|
class MultiURLValidator(DomainlessURLValidator):
|
||||||
|
"""Same as DomainlessURLValidator but supports multiple URLs separated with a comma."""
|
||||||
|
|
||||||
|
def __call__(self, value: str):
|
||||||
|
if "," in value:
|
||||||
|
for url in value.split(","):
|
||||||
|
super().__call__(url)
|
||||||
|
else:
|
||||||
|
super().__call__(value)
|
||||||
|
|
||||||
|
|
||||||
class LDAPSource(Source):
|
class LDAPSource(Source):
|
||||||
"""Federate LDAP Directory with authentik, or create new accounts in LDAP."""
|
"""Federate LDAP Directory with authentik, or create new accounts in LDAP."""
|
||||||
|
|
||||||
server_uri = models.TextField(
|
server_uri = models.TextField(
|
||||||
validators=[DomainlessURLValidator(schemes=["ldap", "ldaps"])],
|
validators=[MultiURLValidator(schemes=["ldap", "ldaps"])],
|
||||||
verbose_name=_("Server URI"),
|
verbose_name=_("Server URI"),
|
||||||
)
|
)
|
||||||
bind_cn = models.TextField(verbose_name=_("Bind CN"), blank=True)
|
bind_cn = models.TextField(verbose_name=_("Bind CN"), blank=True)
|
||||||
|
@ -88,9 +99,15 @@ class LDAPSource(Source):
|
||||||
def connection(self) -> Connection:
|
def connection(self) -> Connection:
|
||||||
"""Get a fully connected and bound LDAP Connection"""
|
"""Get a fully connected and bound LDAP Connection"""
|
||||||
if not self._connection:
|
if not self._connection:
|
||||||
server = Server(self.server_uri, get_info=ALL, connect_timeout=LDAP_TIMEOUT)
|
servers = []
|
||||||
|
if "," in self.server_uri:
|
||||||
|
for server in self.server_uri.split(","):
|
||||||
|
servers.append(Server(server, get_info=ALL, connect_timeout=LDAP_TIMEOUT))
|
||||||
|
else:
|
||||||
|
servers = [Server(self.server_uri, get_info=ALL, connect_timeout=LDAP_TIMEOUT)]
|
||||||
|
pool = ServerPool(servers, ROUND_ROBIN, active=True, exhaust=True)
|
||||||
self._connection = Connection(
|
self._connection = Connection(
|
||||||
server,
|
pool,
|
||||||
raise_exceptions=True,
|
raise_exceptions=True,
|
||||||
user=self.bind_cn,
|
user=self.bind_cn,
|
||||||
password=self.bind_password,
|
password=self.bind_password,
|
||||||
|
|
|
@ -4199,6 +4199,10 @@ msgstr "Sources"
|
||||||
msgid "Sources of identities, which can either be synced into authentik's database, or can be used by users to authenticate and enroll themselves."
|
msgid "Sources of identities, which can either be synced into authentik's database, or can be used by users to authenticate and enroll themselves."
|
||||||
msgstr "Sources of identities, which can either be synced into authentik's database, or can be used by users to authenticate and enroll themselves."
|
msgstr "Sources of identities, which can either be synced into authentik's database, or can be used by users to authenticate and enroll themselves."
|
||||||
|
|
||||||
|
#: src/pages/sources/ldap/LDAPSourceForm.ts
|
||||||
|
msgid "Specify multiple server URIs by separating them with a comma."
|
||||||
|
msgstr "Specify multiple server URIs by separating them with a comma."
|
||||||
|
|
||||||
#: src/pages/flows/BoundStagesList.ts
|
#: src/pages/flows/BoundStagesList.ts
|
||||||
#: src/pages/flows/StageBindingForm.ts
|
#: src/pages/flows/StageBindingForm.ts
|
||||||
msgid "Stage"
|
msgid "Stage"
|
||||||
|
|
|
@ -4162,6 +4162,10 @@ msgstr "Sources"
|
||||||
msgid "Sources of identities, which can either be synced into authentik's database, or can be used by users to authenticate and enroll themselves."
|
msgid "Sources of identities, which can either be synced into authentik's database, or can be used by users to authenticate and enroll themselves."
|
||||||
msgstr "Sources d'identités, qui peuvent soit être synchronisées dans la base de données d'Authentik, soit être utilisées par les utilisateurs pour s'authentifier et s'inscrire."
|
msgstr "Sources d'identités, qui peuvent soit être synchronisées dans la base de données d'Authentik, soit être utilisées par les utilisateurs pour s'authentifier et s'inscrire."
|
||||||
|
|
||||||
|
#: src/pages/sources/ldap/LDAPSourceForm.ts
|
||||||
|
msgid "Specify multiple server URIs by separating them with a comma."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/flows/BoundStagesList.ts
|
#: src/pages/flows/BoundStagesList.ts
|
||||||
#: src/pages/flows/StageBindingForm.ts
|
#: src/pages/flows/StageBindingForm.ts
|
||||||
msgid "Stage"
|
msgid "Stage"
|
||||||
|
|
|
@ -4191,6 +4191,10 @@ msgstr ""
|
||||||
msgid "Sources of identities, which can either be synced into authentik's database, or can be used by users to authenticate and enroll themselves."
|
msgid "Sources of identities, which can either be synced into authentik's database, or can be used by users to authenticate and enroll themselves."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/sources/ldap/LDAPSourceForm.ts
|
||||||
|
msgid "Specify multiple server URIs by separating them with a comma."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/flows/BoundStagesList.ts
|
#: src/pages/flows/BoundStagesList.ts
|
||||||
#: src/pages/flows/StageBindingForm.ts
|
#: src/pages/flows/StageBindingForm.ts
|
||||||
msgid "Stage"
|
msgid "Stage"
|
||||||
|
|
|
@ -124,6 +124,9 @@ export class LDAPSourceForm extends ModelForm<LDAPSource, string> {
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<p class="pf-c-form__helper-text">
|
||||||
|
${t`Specify multiple server URIs by separating them with a comma.`}
|
||||||
|
</p>
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
<ak-form-element-horizontal name="startTls">
|
<ak-form-element-horizontal name="startTls">
|
||||||
<div class="pf-c-check">
|
<div class="pf-c-check">
|
||||||
|
|
|
@ -43,6 +43,10 @@ Use these settings:
|
||||||
|
|
||||||
For authentik to be able to write passwords back to Active Directory, make sure to use `ldaps://`
|
For authentik to be able to write passwords back to Active Directory, make sure to use `ldaps://`
|
||||||
|
|
||||||
|
You can specify multiple servers by separating URIs with a comma, like `ldap://dc1.ad.company,ldap://dc2.ad.company`.
|
||||||
|
|
||||||
|
When using a DNS entry with multiple Records, authentik will select a random entry when first connecting.
|
||||||
|
|
||||||
- Bind CN: `<name of your service user>@ad.company`
|
- Bind CN: `<name of your service user>@ad.company`
|
||||||
- Bind Password: The password you've given the user above
|
- Bind Password: The password you've given the user above
|
||||||
- Base DN: The base DN which you want authentik to sync
|
- Base DN: The base DN which you want authentik to sync
|
||||||
|
|
|
@ -45,6 +45,11 @@ In authentik, create a new LDAP Source in Resources -> Sources.
|
||||||
Use these settings:
|
Use these settings:
|
||||||
|
|
||||||
- Server URI: `ldaps://ipa1.freeipa.company`
|
- Server URI: `ldaps://ipa1.freeipa.company`
|
||||||
|
|
||||||
|
You can specify multiple servers by separating URIs with a comma, like `ldap://ipa1.freeipa.company,ldap://ipa2.freeipa.company`.
|
||||||
|
|
||||||
|
When using a DNS entry with multiple Records, authentik will select a random entry when first connecting.
|
||||||
|
|
||||||
- Bind CN: `uid=svc_authentik,cn=users,cn=accounts,dc=freeipa,dc=company`
|
- Bind CN: `uid=svc_authentik,cn=users,cn=accounts,dc=freeipa,dc=company`
|
||||||
- Bind Password: The password you've given the user above
|
- Bind Password: The password you've given the user above
|
||||||
- Base DN: `dc=freeipa,dc=company`
|
- Base DN: `dc=freeipa,dc=company`
|
||||||
|
|
|
@ -15,6 +15,11 @@ For FreeIPA, follow the [FreeIPA Integration](../freeipa/index.md)
|
||||||
:::
|
:::
|
||||||
|
|
||||||
- Server URI: URI to your LDAP server/Domain Controller.
|
- Server URI: URI to your LDAP server/Domain Controller.
|
||||||
|
|
||||||
|
You can specify multiple servers by separating URIs with a comma, like `ldap://ldap1.company,ldap://ldap2.company`.
|
||||||
|
|
||||||
|
When using a DNS entry with multiple Records, authentik will select a random entry when first connecting.
|
||||||
|
|
||||||
- Bind CN: CN of the bind user. This can also be a UPN in the format of `user@domain.tld`.
|
- Bind CN: CN of the bind user. This can also be a UPN in the format of `user@domain.tld`.
|
||||||
- Bind password: Password used during the bind process.
|
- Bind password: Password used during the bind process.
|
||||||
- Enable StartTLS: Enables StartTLS functionality. To use LDAPS instead, use port `636`.
|
- Enable StartTLS: Enables StartTLS functionality. To use LDAPS instead, use port `636`.
|
||||||
|
|
Reference in New Issue