From f1b9021e3ee52f5d8f7bca151dc990033b78f274 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Fri, 3 Dec 2021 10:09:13 +0100 Subject: [PATCH] sources/ldap: add optional tls verification certificate closes #1875 Signed-off-by: Jens Langhammer --- authentik/sources/ldap/api.py | 5 +-- .../migrations/0002_auto_20211203_0900.py | 38 ++++++++++++++++++ authentik/sources/ldap/models.py | 27 +++++++++++-- schema.yml | 34 +++++++++------- web/src/locales/en.po | 6 +++ web/src/locales/fr_FR.po | 6 +++ web/src/locales/pseudo-LOCALE.po | 6 +++ web/src/pages/sources/ldap/LDAPSourceForm.ts | 39 +++++++++++++++++++ 8 files changed, 141 insertions(+), 20 deletions(-) create mode 100644 authentik/sources/ldap/migrations/0002_auto_20211203_0900.py diff --git a/authentik/sources/ldap/api.py b/authentik/sources/ldap/api.py index aae8e643a..7b1413c4b 100644 --- a/authentik/sources/ldap/api.py +++ b/authentik/sources/ldap/api.py @@ -43,6 +43,7 @@ class LDAPSourceSerializer(SourceSerializer): model = LDAPSource fields = SourceSerializer.Meta.fields + [ "server_uri", + "peer_certificate", "bind_cn", "bind_password", "start_tls", @@ -73,11 +74,9 @@ class LDAPSourceViewSet(UsedByMixin, ModelViewSet): "name", "slug", "enabled", - "authentication_flow", - "enrollment_flow", - "policy_engine_mode", "server_uri", "bind_cn", + "peer_certificate", "start_tls", "base_dn", "additional_user_dn", diff --git a/authentik/sources/ldap/migrations/0002_auto_20211203_0900.py b/authentik/sources/ldap/migrations/0002_auto_20211203_0900.py new file mode 100644 index 000000000..2161b7cbf --- /dev/null +++ b/authentik/sources/ldap/migrations/0002_auto_20211203_0900.py @@ -0,0 +1,38 @@ +# Generated by Django 3.2.9 on 2021-12-03 09:00 + +import django.db.models.deletion +from django.db import migrations, models + +import authentik.sources.ldap.models + + +class Migration(migrations.Migration): + + dependencies = [ + ("authentik_crypto", "0003_certificatekeypair_managed"), + ("authentik_sources_ldap", "0001_squashed_0012_auto_20210812_1703"), + ] + + operations = [ + migrations.AddField( + model_name="ldapsource", + name="peer_certificate", + field=models.ForeignKey( + default=None, + help_text="Optionally verify the LDAP Server's Certificate against the CA Chain in this keypair.", + null=True, + on_delete=django.db.models.deletion.SET_DEFAULT, + to="authentik_crypto.certificatekeypair", + ), + ), + migrations.AlterField( + model_name="ldapsource", + name="server_uri", + field=models.TextField( + validators=[ + authentik.sources.ldap.models.MultiURLValidator(schemes=["ldap", "ldaps"]) + ], + verbose_name="Server URI", + ), + ), + ] diff --git a/authentik/sources/ldap/models.py b/authentik/sources/ldap/models.py index 1e9535849..ade91978e 100644 --- a/authentik/sources/ldap/models.py +++ b/authentik/sources/ldap/models.py @@ -1,12 +1,14 @@ """authentik LDAP Models""" +from ssl import CERT_REQUIRED from typing import Type from django.db import models from django.utils.translation import gettext_lazy as _ -from ldap3 import ALL, RANDOM, Connection, Server, ServerPool +from ldap3 import ALL, RANDOM, Connection, Server, ServerPool, Tls from rest_framework.serializers import Serializer from authentik.core.models import Group, PropertyMapping, Source +from authentik.crypto.models import CertificateKeyPair from authentik.lib.models import DomainlessURLValidator LDAP_TIMEOUT = 15 @@ -30,6 +32,17 @@ class LDAPSource(Source): validators=[MultiURLValidator(schemes=["ldap", "ldaps"])], verbose_name=_("Server URI"), ) + peer_certificate = models.ForeignKey( + CertificateKeyPair, + on_delete=models.SET_DEFAULT, + default=None, + null=True, + help_text=_( + "Optionally verify the LDAP Server's Certificate " + "against the CA Chain in this keypair." + ), + ) + bind_cn = models.TextField(verbose_name=_("Bind CN"), blank=True) bind_password = models.TextField(blank=True) start_tls = models.BooleanField(default=False, verbose_name=_("Enable Start TLS")) @@ -97,11 +110,19 @@ class LDAPSource(Source): def server(self) -> Server: """Get LDAP Server/ServerPool""" servers = [] + tls = Tls() + if self.peer_certificate: + tls = Tls(ca_certs_data=self.peer_certificate.certificate_data, validate=CERT_REQUIRED) + kwargs = { + "get_info": ALL, + "connect_timeout": LDAP_TIMEOUT, + "tls": tls, + } if "," in self.server_uri: for server in self.server_uri.split(","): - servers.append(Server(server, get_info=ALL, connect_timeout=LDAP_TIMEOUT)) + servers.append(Server(server, **kwargs)) else: - servers = [Server(self.server_uri, get_info=ALL, connect_timeout=LDAP_TIMEOUT)] + servers = [Server(self.server_uri, **kwargs)] return ServerPool(servers, RANDOM, active=True, exhaust=True) @property diff --git a/schema.yml b/schema.yml index 77905dc2b..28dae5da6 100644 --- a/schema.yml +++ b/schema.yml @@ -12058,11 +12058,6 @@ paths: name: additional_user_dn schema: type: string - - in: query - name: authentication_flow - schema: - type: string - format: uuid - in: query name: base_dn schema: @@ -12075,11 +12070,6 @@ paths: name: enabled schema: type: boolean - - in: query - name: enrollment_flow - schema: - type: string - format: uuid - in: query name: group_membership_field schema: @@ -12115,12 +12105,10 @@ paths: schema: type: integer - in: query - name: policy_engine_mode + name: peer_certificate schema: type: string - enum: - - all - - any + format: uuid - in: query name: property_mappings schema: @@ -22461,6 +22449,12 @@ components: server_uri: type: string format: uri + peer_certificate: + type: string + format: uuid + nullable: true + description: Optionally verify the LDAP Server's Certificate against the + CA Chain in this keypair. bind_cn: type: string start_tls: @@ -22558,6 +22552,12 @@ components: type: string minLength: 1 format: uri + peer_certificate: + type: string + format: uuid + nullable: true + description: Optionally verify the LDAP Server's Certificate against the + CA Chain in this keypair. bind_cn: type: string bind_password: @@ -27181,6 +27181,12 @@ components: type: string minLength: 1 format: uri + peer_certificate: + type: string + format: uuid + nullable: true + description: Optionally verify the LDAP Server's Certificate against the + CA Chain in this keypair. bind_cn: type: string bind_password: diff --git a/web/src/locales/en.po b/web/src/locales/en.po index 15bc01096..8a93dad05 100644 --- a/web/src/locales/en.po +++ b/web/src/locales/en.po @@ -2608,6 +2608,7 @@ msgstr "Loading" #: src/pages/sources/ldap/LDAPSourceForm.ts #: src/pages/sources/ldap/LDAPSourceForm.ts #: src/pages/sources/ldap/LDAPSourceForm.ts +#: src/pages/sources/ldap/LDAPSourceForm.ts #: src/pages/sources/oauth/OAuthSourceForm.ts #: src/pages/sources/oauth/OAuthSourceForm.ts #: src/pages/sources/plex/PlexSourceForm.ts @@ -4743,6 +4744,7 @@ msgstr "TLS Authentication Certificate" #~ msgstr "TLS Server name" #: src/pages/outposts/ServiceConnectionDockerForm.ts +#: src/pages/sources/ldap/LDAPSourceForm.ts msgid "TLS Verification Certificate" msgstr "TLS Verification Certificate" @@ -5651,6 +5653,10 @@ msgstr "When a user returns from the email successfully, their account will be a msgid "When a valid username/email has been entered, and this option is enabled, the user's username and avatar will be shown. Otherwise, the text that the user entered will be shown." msgstr "When a valid username/email has been entered, and this option is enabled, the user's username and avatar will be shown. Otherwise, the text that the user entered will be shown." +#: src/pages/sources/ldap/LDAPSourceForm.ts +msgid "When connecting to an LDAP Server with TLS, certificates are not checked by default. Specify a keypair to validate the remote certificate." +msgstr "When connecting to an LDAP Server with TLS, certificates are not checked by default. Specify a keypair to validate the remote certificate." + #: src/pages/stages/email/EmailStageForm.ts msgid "When enabled, global Email connection settings will be used and connection settings below will be ignored." msgstr "When enabled, global Email connection settings will be used and connection settings below will be ignored." diff --git a/web/src/locales/fr_FR.po b/web/src/locales/fr_FR.po index 39c9ccbc5..8ef47c80a 100644 --- a/web/src/locales/fr_FR.po +++ b/web/src/locales/fr_FR.po @@ -2589,6 +2589,7 @@ msgstr "Chargement en cours" #: src/pages/sources/ldap/LDAPSourceForm.ts #: src/pages/sources/ldap/LDAPSourceForm.ts #: src/pages/sources/ldap/LDAPSourceForm.ts +#: src/pages/sources/ldap/LDAPSourceForm.ts #: src/pages/sources/oauth/OAuthSourceForm.ts #: src/pages/sources/oauth/OAuthSourceForm.ts #: src/pages/sources/plex/PlexSourceForm.ts @@ -4699,6 +4700,7 @@ msgstr "Certificat TLS d'authentification" #~ msgstr "Nom TLS du serveur" #: src/pages/outposts/ServiceConnectionDockerForm.ts +#: src/pages/sources/ldap/LDAPSourceForm.ts msgid "TLS Verification Certificate" msgstr "Certificat de vérification TLS" @@ -5594,6 +5596,10 @@ msgstr "Lorsqu'un utilisateur revient de l'e-mail avec succès, son compte sera msgid "When a valid username/email has been entered, and this option is enabled, the user's username and avatar will be shown. Otherwise, the text that the user entered will be shown." msgstr "Lorsqu'un nom d'utilisateur/email valide a été saisi, et si cette option est active, le nom d'utilisateur et l'avatar de l'utilisateur seront affichés. Sinon, le texte que l'utilisateur a saisi sera affiché." +#: src/pages/sources/ldap/LDAPSourceForm.ts +msgid "When connecting to an LDAP Server with TLS, certificates are not checked by default. Specify a keypair to validate the remote certificate." +msgstr "" + #: src/pages/stages/email/EmailStageForm.ts msgid "When enabled, global Email connection settings will be used and connection settings below will be ignored." msgstr "Si activé, les paramètres globaux de connexion courriel seront utilisés et les paramètres de connexion ci-dessous seront ignorés." diff --git a/web/src/locales/pseudo-LOCALE.po b/web/src/locales/pseudo-LOCALE.po index 102f50448..d3d7b7917 100644 --- a/web/src/locales/pseudo-LOCALE.po +++ b/web/src/locales/pseudo-LOCALE.po @@ -2600,6 +2600,7 @@ msgstr "" #: src/pages/sources/ldap/LDAPSourceForm.ts #: src/pages/sources/ldap/LDAPSourceForm.ts #: src/pages/sources/ldap/LDAPSourceForm.ts +#: src/pages/sources/ldap/LDAPSourceForm.ts #: src/pages/sources/oauth/OAuthSourceForm.ts #: src/pages/sources/oauth/OAuthSourceForm.ts #: src/pages/sources/plex/PlexSourceForm.ts @@ -4735,6 +4736,7 @@ msgstr "" #~ msgstr "" #: src/pages/outposts/ServiceConnectionDockerForm.ts +#: src/pages/sources/ldap/LDAPSourceForm.ts msgid "TLS Verification Certificate" msgstr "" @@ -5636,6 +5638,10 @@ msgstr "" msgid "When a valid username/email has been entered, and this option is enabled, the user's username and avatar will be shown. Otherwise, the text that the user entered will be shown." msgstr "" +#: src/pages/sources/ldap/LDAPSourceForm.ts +msgid "When connecting to an LDAP Server with TLS, certificates are not checked by default. Specify a keypair to validate the remote certificate." +msgstr "" + #: src/pages/stages/email/EmailStageForm.ts msgid "When enabled, global Email connection settings will be used and connection settings below will be ignored." msgstr "" diff --git a/web/src/pages/sources/ldap/LDAPSourceForm.ts b/web/src/pages/sources/ldap/LDAPSourceForm.ts index 9c8982711..59729d5ab 100644 --- a/web/src/pages/sources/ldap/LDAPSourceForm.ts +++ b/web/src/pages/sources/ldap/LDAPSourceForm.ts @@ -7,6 +7,7 @@ import { until } from "lit/directives/until.js"; import { CoreApi, + CryptoApi, LDAPSource, LDAPSourceRequest, PropertymappingsApi, @@ -141,6 +142,44 @@ export class LDAPSourceForm extends ModelForm { ${t`To use SSL instead, use 'ldaps://' and disable this option.`}

+ + +

+ ${t`When connecting to an LDAP Server with TLS, certificates are not checked by default. Specify a keypair to validate the remote certificate.`} +

+