From 029395d08bab1fa7b6fcf2cb6ad291e6b2b4e8ba Mon Sep 17 00:00:00 2001 From: ChandonPierre <80500072+ChandonPierre@users.noreply.github.com> Date: Mon, 12 Jun 2023 09:41:44 -0400 Subject: [PATCH] sources/ldap: add support for cert based auth (#5850) * ldap: support cert based auth Signed-off-by: Jens Langhammer * ldap: default sni switch to off * ldap: `get_info=NONE` on insufficient access error * fix: Make file locale script * ldap: add google ldap attribute mappings * ldap: move google secure ldap blueprint to examples Revert "ldap: add google ldap attribute mappings" This reverts commit 8a861bb92c1bd763b6e7ec0513f73b3039a1adb4. * ldap: remove `validate` for client cert auth not strictly necessary * ldap: write temp cert files more securely * ldap: use first array value for sni when provided csv input * don't specify tempdir we set $TMPDIR in the dockerfile Signed-off-by: Jens Langhammer * limit API to only allow certificate key pairs with private key Signed-off-by: Jens Langhammer * use maxsplit Signed-off-by: Jens Langhammer * update locale Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer Signed-off-by: Jens L. Co-authored-by: Jens Langhammer --- Makefile | 2 +- authentik/sources/ldap/api.py | 15 ++ ...ent_certificate_ldapsource_sni_and_more.py | 45 ++++ authentik/sources/ldap/models.py | 37 ++- .../example/sources-google-ldap-mappings.yaml | 222 ++++++++++++++++++ blueprints/schema.json | 9 + locale/en/LC_MESSAGES/django.po | 91 +++---- schema.yml | 36 +++ web/src/admin/sources/ldap/LDAPSourceForm.ts | 59 +++++ web/xliff/de.xlf | 28 ++- web/xliff/en.xlf | 29 ++- web/xliff/es.xlf | 28 ++- web/xliff/fr_FR.xlf | 28 ++- web/xliff/pl.xlf | 28 ++- web/xliff/pseudo-LOCALE.xlf | 29 ++- web/xliff/tr.xlf | 28 ++- web/xliff/zh-Hans.xlf | 31 ++- web/xliff/zh-Hant.xlf | 28 ++- web/xliff/zh_TW.xlf | 28 ++- 19 files changed, 680 insertions(+), 121 deletions(-) create mode 100644 authentik/sources/ldap/migrations/0003_ldapsource_client_certificate_ldapsource_sni_and_more.py create mode 100644 blueprints/example/sources-google-ldap-mappings.yaml diff --git a/Makefile b/Makefile index 1943e85b4..dcd8e73ca 100644 --- a/Makefile +++ b/Makefile @@ -151,7 +151,7 @@ web-check-compile: cd web && npm run tsc web-i18n-extract: - cd web && npm run extract + cd web && npm run extract-locales ######################### ## Website diff --git a/authentik/sources/ldap/api.py b/authentik/sources/ldap/api.py index 3f6e24837..0a8849345 100644 --- a/authentik/sources/ldap/api.py +++ b/authentik/sources/ldap/api.py @@ -8,6 +8,7 @@ from drf_spectacular.utils import extend_schema, extend_schema_field, inline_ser from rest_framework.decorators import action from rest_framework.exceptions import ValidationError from rest_framework.fields import DictField, ListField +from rest_framework.relations import PrimaryKeyRelatedField from rest_framework.request import Request from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet @@ -16,6 +17,7 @@ from authentik.admin.api.tasks import TaskSerializer from authentik.core.api.propertymappings import PropertyMappingSerializer from authentik.core.api.sources import SourceSerializer from authentik.core.api.used_by import UsedByMixin +from authentik.crypto.models import CertificateKeyPair from authentik.events.monitored_tasks import TaskInfo from authentik.sources.ldap.models import LDAPPropertyMapping, LDAPSource from authentik.sources.ldap.tasks import SYNC_CLASSES @@ -24,6 +26,15 @@ from authentik.sources.ldap.tasks import SYNC_CLASSES class LDAPSourceSerializer(SourceSerializer): """LDAP Source Serializer""" + client_certificate = PrimaryKeyRelatedField( + allow_null=True, + help_text="Client certificate to authenticate against the LDAP Server's Certificate.", + queryset=CertificateKeyPair.objects.exclude( + key_data__exact="", + ), + required=False, + ) + def validate(self, attrs: dict[str, Any]) -> dict[str, Any]: """Check that only a single source has password_sync on""" sync_users_password = attrs.get("sync_users_password", True) @@ -42,9 +53,11 @@ class LDAPSourceSerializer(SourceSerializer): fields = SourceSerializer.Meta.fields + [ "server_uri", "peer_certificate", + "client_certificate", "bind_cn", "bind_password", "start_tls", + "sni", "base_dn", "additional_user_dn", "additional_group_dn", @@ -75,7 +88,9 @@ class LDAPSourceViewSet(UsedByMixin, ModelViewSet): "server_uri", "bind_cn", "peer_certificate", + "client_certificate", "start_tls", + "sni", "base_dn", "additional_user_dn", "additional_group_dn", diff --git a/authentik/sources/ldap/migrations/0003_ldapsource_client_certificate_ldapsource_sni_and_more.py b/authentik/sources/ldap/migrations/0003_ldapsource_client_certificate_ldapsource_sni_and_more.py new file mode 100644 index 000000000..7c67597bb --- /dev/null +++ b/authentik/sources/ldap/migrations/0003_ldapsource_client_certificate_ldapsource_sni_and_more.py @@ -0,0 +1,45 @@ +# Generated by Django 4.1.7 on 2023-06-06 18:33 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("authentik_crypto", "0004_alter_certificatekeypair_name"), + ("authentik_sources_ldap", "0002_auto_20211203_0900"), + ] + + operations = [ + migrations.AddField( + model_name="ldapsource", + name="client_certificate", + field=models.ForeignKey( + default=None, + help_text="Client certificate to authenticate against the LDAP Server's Certificate.", + null=True, + on_delete=django.db.models.deletion.SET_DEFAULT, + related_name="ldap_client_certificates", + to="authentik_crypto.certificatekeypair", + ), + ), + migrations.AddField( + model_name="ldapsource", + name="sni", + field=models.BooleanField( + default=False, verbose_name="Use Server URI for SNI verification" + ), + ), + migrations.AlterField( + 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, + related_name="ldap_peer_certificates", + to="authentik_crypto.certificatekeypair", + ), + ), + ] diff --git a/authentik/sources/ldap/models.py b/authentik/sources/ldap/models.py index 2b4acbedf..4a6c2fd2e 100644 --- a/authentik/sources/ldap/models.py +++ b/authentik/sources/ldap/models.py @@ -1,11 +1,13 @@ """authentik LDAP Models""" +from os import chmod from ssl import CERT_REQUIRED +from tempfile import NamedTemporaryFile, mkdtemp from typing import Optional from django.db import models from django.utils.translation import gettext_lazy as _ from ldap3 import ALL, NONE, RANDOM, Connection, Server, ServerPool, Tls -from ldap3.core.exceptions import LDAPSchemaError +from ldap3.core.exceptions import LDAPInsufficientAccessRightsResult, LDAPSchemaError from rest_framework.serializers import Serializer from authentik.core.models import Group, PropertyMapping, Source @@ -39,14 +41,24 @@ class LDAPSource(Source): on_delete=models.SET_DEFAULT, default=None, null=True, + related_name="ldap_peer_certificates", help_text=_( "Optionally verify the LDAP Server's Certificate against the CA Chain in this keypair." ), ) + client_certificate = models.ForeignKey( + CertificateKeyPair, + on_delete=models.SET_DEFAULT, + default=None, + null=True, + related_name="ldap_client_certificates", + help_text=_("Client certificate to authenticate against the LDAP Server's Certificate."), + ) 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")) + sni = models.BooleanField(default=False, verbose_name=_("Use Server URI for SNI verification")) base_dn = models.TextField(verbose_name=_("Base DN")) additional_user_dn = models.TextField( @@ -112,8 +124,22 @@ class LDAPSource(Source): if self.peer_certificate: tls_kwargs["ca_certs_data"] = self.peer_certificate.certificate_data tls_kwargs["validate"] = CERT_REQUIRED + if self.client_certificate: + temp_dir = mkdtemp() + with NamedTemporaryFile(mode="w", delete=False, dir=temp_dir) as temp_cert: + temp_cert.write(self.client_certificate.certificate_data) + certificate_file = temp_cert.name + chmod(certificate_file, 0o600) + with NamedTemporaryFile(mode="w", delete=False, dir=temp_dir) as temp_key: + temp_key.write(self.client_certificate.key_data) + private_key_file = temp_key.name + chmod(private_key_file, 0o600) + tls_kwargs["local_private_key_file"] = private_key_file + tls_kwargs["local_certificate_file"] = certificate_file if ciphers := CONFIG.y("ldap.tls.ciphers", None): tls_kwargs["ciphers"] = ciphers.strip() + if self.sni: + tls_kwargs["sni"] = self.server_uri.split(",", maxsplit=1)[0].strip() server_kwargs = { "get_info": ALL, "connect_timeout": LDAP_TIMEOUT, @@ -133,8 +159,10 @@ class LDAPSource(Source): """Get a fully connected and bound LDAP Connection""" server_kwargs = server_kwargs or {} connection_kwargs = connection_kwargs or {} - connection_kwargs.setdefault("user", self.bind_cn) - connection_kwargs.setdefault("password", self.bind_password) + if self.bind_cn is not None: + connection_kwargs.setdefault("user", self.bind_cn) + if self.bind_password is not None: + connection_kwargs.setdefault("password", self.bind_password) connection = Connection( self.server(**server_kwargs), raise_exceptions=True, @@ -148,9 +176,10 @@ class LDAPSource(Source): successful = connection.bind() if successful: return connection - except LDAPSchemaError as exc: + except (LDAPSchemaError, LDAPInsufficientAccessRightsResult) as exc: # Schema error, so try connecting without schema info # See https://github.com/goauthentik/authentik/issues/4590 + # See also https://github.com/goauthentik/authentik/issues/3399 if server_kwargs.get("get_info", ALL) == NONE: raise exc server_kwargs["get_info"] = NONE diff --git a/blueprints/example/sources-google-ldap-mappings.yaml b/blueprints/example/sources-google-ldap-mappings.yaml new file mode 100644 index 000000000..e070798dd --- /dev/null +++ b/blueprints/example/sources-google-ldap-mappings.yaml @@ -0,0 +1,222 @@ +version: 1 +metadata: + labels: + blueprints.goauthentik.io/instantiate: "false" + name: Example - Google Secure LDAP mappings +entries: + - identifiers: + managed: goauthentik.io/sources/ldap/google-uid + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: uid" + object_field: "username" + expression: | + return ldap.get('uid') + - identifiers: + managed: goauthentik.io/sources/ldap/google-googleuid + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: googleUid" + object_field: "attributes.googleUid" + expression: | + return ldap.get('googleUid') + - identifiers: + managed: goauthentik.io/sources/ldap/google-posixuid + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: posixUid" + object_field: "attributes.posixUid" + expression: | + return ldap.get('posixUid') + - identifiers: + managed: goauthentik.io/sources/ldap/google-cn + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: cn" + object_field: "name" + expression: | + return ldap.get('cn') + - identifiers: + managed: goauthentik.io/sources/ldap/google-sn + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: sn" + object_field: "attributes.sn" + expression: | + return list_flatten(ldap.get('sn')) + - identifiers: + managed: goauthentik.io/sources/ldap/google-givenname + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: givenName" + object_field: "attributes.givenName" + expression: | + return list_flatten(ldap.get('givenName')) + - identifiers: + managed: goauthentik.io/sources/ldap/google-displayname + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: displayName" + object_field: "attributes.displayName" + expression: | + return ldap.get('displayName') + - identifiers: + managed: goauthentik.io/sources/ldap/google-mail + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: mail" + object_field: "email" + expression: | + return ldap.get('mail') + - identifiers: + managed: goauthentik.io/sources/ldap/google-memberof + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: memberOf" + object_field: "attributes.memberOf" + expression: | + return ldap.get('memberOf') + - identifiers: + managed: goauthentik.io/sources/ldap/google-title + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: title" + object_field: "attributes.title" + expression: | + return ldap.get('title') + - identifiers: + managed: goauthentik.io/sources/ldap/google-employeenumber + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: employeeNumber" + object_field: "attributes.employeeNumber" + expression: | + return ldap.get('employeeNumber') + - identifiers: + managed: goauthentik.io/sources/ldap/google-employeetype + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: employeeType" + object_field: "attributes.employeeType" + expression: | + return ldap.get('employeeType') + - identifiers: + managed: goauthentik.io/sources/ldap/google-departmentnumber + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: departmentNumber" + object_field: "attributes.departmentNumber" + expression: | + return ldap.get('departmentNumber') + - identifiers: + managed: goauthentik.io/sources/ldap/google-physicaldeliveryofficename + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: physicalDeliveryOfficeName" + object_field: "attributes.physicalDeliveryOfficeName" + expression: | + return ldap.get('physicalDeliveryOfficeName') + - identifiers: + managed: goauthentik.io/sources/ldap/google-jpegphoto + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: jpegPhoto" + object_field: "attributes.jpegPhoto" + expression: | + return ldap.get('jpegPhoto') + - identifiers: + managed: goauthentik.io/sources/ldap/google-entryuuid + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: entryUuid" + object_field: "attributes.entryUuid" + expression: | + return ldap.get('entryUuid') + - identifiers: + managed: goauthentik.io/sources/ldap/google-objectsid + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: objectSid" + object_field: "attributes.objectSid" + expression: | + return ldap.get('objectSid') + - identifiers: + managed: goauthentik.io/sources/ldap/google-uidnumber + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: uidNumber" + object_field: "attributes.uidNumber" + expression: | + return ldap.get('uidNumber') + - identifiers: + managed: goauthentik.io/sources/ldap/google-gidnumber + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: gidNumber" + object_field: "attributes.gidNumber" + expression: | + return ldap.get('gidNumber') + - identifiers: + managed: goauthentik.io/sources/ldap/google-homedirectory + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: homeDirectory" + object_field: "attributes.homeDirectory" + expression: | + return ldap.get('homeDirectory') + - identifiers: + managed: goauthentik.io/sources/ldap/google-loginshell + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: loginShell" + object_field: "attributes.loginShell" + expression: | + return ldap.get('loginShell') + - identifiers: + managed: goauthentik.io/sources/ldap/google-gidnumber + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: gidNumber" + object_field: "attributes.gidNumber" + expression: | + return ldap.get('gidNumber') + - identifiers: + managed: goauthentik.io/sources/ldap/google-sshpublickey + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: sshPublicKey" + object_field: "attributes.sshPublicKey" + expression: | + return list_flatten(ldap.get('sshPublicKey')) + - identifiers: + managed: goauthentik.io/sources/ldap/google-description + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: description" + object_field: "attributes.description" + expression: | + return list_flatten(ldap.get('description')) + - identifiers: + managed: goauthentik.io/sources/ldap/google-member + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: member" + object_field: "attributes.member" + expression: | + return list_flatten(ldap.get('member')) + - identifiers: + managed: goauthentik.io/sources/ldap/google-memberuid + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: memberUid" + object_field: "attributes.memberUid" + expression: | + return list_flatten(ldap.get('memberUid')) + - identifiers: + managed: goauthentik.io/sources/ldap/google-googleadmincreated + model: authentik_sources_ldap.ldappropertymapping + attrs: + name: "Google Secure LDAP Mapping: googleAdminCreated" + object_field: "attributes.googleAdminCreated" + expression: | + return list_flatten(ldap.get('googleAdminCreated')) diff --git a/blueprints/schema.json b/blueprints/schema.json index 9422fbc79..edbc7f81b 100644 --- a/blueprints/schema.json +++ b/blueprints/schema.json @@ -4732,6 +4732,11 @@ "title": "Peer certificate", "description": "Optionally verify the LDAP Server's Certificate against the CA Chain in this keypair." }, + "client_certificate": { + "type": "integer", + "title": "Client certificate", + "description": "Client certificate to authenticate against the LDAP Server's Certificate." + }, "bind_cn": { "type": "string", "title": "Bind CN" @@ -4744,6 +4749,10 @@ "type": "boolean", "title": "Enable Start TLS" }, + "sni": { + "type": "boolean", + "title": "Use Server URI for SNI verification" + }, "base_dn": { "type": "string", "minLength": 1, diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index 7499d20f4..a8e43fce6 100644 --- a/locale/en/LC_MESSAGES/django.po +++ b/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-21 21:59+0000\n" +"POT-Creation-Date: 2023-06-12 12:11+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -31,16 +31,16 @@ msgstr "" msgid "Validation Error" msgstr "" -#: authentik/blueprints/api.py:43 +#: authentik/blueprints/api.py:44 msgid "Blueprint file does not exist" msgstr "" -#: authentik/blueprints/api.py:54 +#: authentik/blueprints/api.py:55 #, python-format msgid "Failed to validate blueprint: %(logs)s" msgstr "" -#: authentik/blueprints/api.py:59 +#: authentik/blueprints/api.py:60 msgid "Either path or content must be set." msgstr "" @@ -69,24 +69,24 @@ msgstr "" msgid "authentik Export - %(date)s" msgstr "" -#: authentik/blueprints/v1/tasks.py:149 authentik/crypto/tasks.py:93 +#: authentik/blueprints/v1/tasks.py:150 authentik/crypto/tasks.py:93 #, python-format msgid "Successfully imported %(count)d files." msgstr "" -#: authentik/core/api/providers.py:113 +#: authentik/core/api/providers.py:120 msgid "SAML Provider from Metadata" msgstr "" -#: authentik/core/api/providers.py:114 +#: authentik/core/api/providers.py:121 msgid "Create a SAML Provider by importing its Metadata." msgstr "" -#: authentik/core/api/users.py:118 +#: authentik/core/api/users.py:143 msgid "No leading or trailing slashes allowed." msgstr "" -#: authentik/core/api/users.py:121 +#: authentik/core/api/users.py:146 msgid "No empty segments in user path allowed." msgstr "" @@ -1365,7 +1365,7 @@ msgstr "" msgid "Authentication token" msgstr "" -#: authentik/providers/scim/models.py:33 authentik/sources/ldap/models.py:82 +#: authentik/providers/scim/models.py:33 authentik/sources/ldap/models.py:94 msgid "Property mappings used for group creation/updating." msgstr "" @@ -1426,79 +1426,88 @@ msgstr "" msgid "Used recovery-link to authenticate." msgstr "" -#: authentik/sources/ldap/models.py:35 +#: authentik/sources/ldap/models.py:37 msgid "Server URI" msgstr "" -#: authentik/sources/ldap/models.py:43 +#: authentik/sources/ldap/models.py:46 msgid "" "Optionally verify the LDAP Server's Certificate against the CA Chain in this " "keypair." msgstr "" -#: authentik/sources/ldap/models.py:47 -msgid "Bind CN" -msgstr "" - -#: authentik/sources/ldap/models.py:49 -msgid "Enable Start TLS" -msgstr "" - -#: authentik/sources/ldap/models.py:51 -msgid "Base DN" -msgstr "" - -#: authentik/sources/ldap/models.py:53 -msgid "Prepended to Base DN for User-queries." -msgstr "" - -#: authentik/sources/ldap/models.py:54 -msgid "Addition User DN" +#: authentik/sources/ldap/models.py:55 +msgid "" +"Client certificate to authenticate against the LDAP Server's Certificate." msgstr "" #: authentik/sources/ldap/models.py:58 -msgid "Prepended to Base DN for Group-queries." +msgid "Bind CN" msgstr "" -#: authentik/sources/ldap/models.py:59 -msgid "Addition Group DN" +#: authentik/sources/ldap/models.py:60 +msgid "Enable Start TLS" +msgstr "" + +#: authentik/sources/ldap/models.py:61 +msgid "Use Server URI for SNI verification" +msgstr "" + +#: authentik/sources/ldap/models.py:63 +msgid "Base DN" msgstr "" #: authentik/sources/ldap/models.py:65 +msgid "Prepended to Base DN for User-queries." +msgstr "" + +#: authentik/sources/ldap/models.py:66 +msgid "Addition User DN" +msgstr "" + +#: authentik/sources/ldap/models.py:70 +msgid "Prepended to Base DN for Group-queries." +msgstr "" + +#: authentik/sources/ldap/models.py:71 +msgid "Addition Group DN" +msgstr "" + +#: authentik/sources/ldap/models.py:77 msgid "Consider Objects matching this filter to be Users." msgstr "" -#: authentik/sources/ldap/models.py:68 +#: authentik/sources/ldap/models.py:80 msgid "Field which contains members of a group." msgstr "" -#: authentik/sources/ldap/models.py:72 +#: authentik/sources/ldap/models.py:84 msgid "Consider Objects matching this filter to be Groups." msgstr "" -#: authentik/sources/ldap/models.py:75 +#: authentik/sources/ldap/models.py:87 msgid "Field which contains a unique Identifier." msgstr "" -#: authentik/sources/ldap/models.py:89 +#: authentik/sources/ldap/models.py:101 msgid "" "When a user changes their password, sync it back to LDAP. This can only be " "enabled on a single LDAP source." msgstr "" -#: authentik/sources/ldap/models.py:159 +#: authentik/sources/ldap/models.py:188 msgid "LDAP Source" msgstr "" -#: authentik/sources/ldap/models.py:160 +#: authentik/sources/ldap/models.py:189 msgid "LDAP Sources" msgstr "" -#: authentik/sources/ldap/models.py:182 +#: authentik/sources/ldap/models.py:211 msgid "LDAP Property Mapping" msgstr "" -#: authentik/sources/ldap/models.py:183 +#: authentik/sources/ldap/models.py:212 msgid "LDAP Property Mappings" msgstr "" diff --git a/schema.yml b/schema.yml index 5ac3ccba5..63065ceee 100644 --- a/schema.yml +++ b/schema.yml @@ -17096,6 +17096,11 @@ paths: name: bind_cn schema: type: string + - in: query + name: client_certificate + schema: + type: string + format: uuid - in: query name: enabled schema: @@ -17171,6 +17176,10 @@ paths: name: slug schema: type: string + - in: query + name: sni + schema: + type: boolean - in: query name: start_tls schema: @@ -30950,11 +30959,20 @@ components: nullable: true description: Optionally verify the LDAP Server's Certificate against the CA Chain in this keypair. + client_certificate: + type: string + format: uuid + nullable: true + description: Client certificate to authenticate against the LDAP Server's + Certificate. bind_cn: type: string start_tls: type: boolean title: Enable Start TLS + sni: + type: boolean + title: Use Server URI for SNI verification base_dn: type: string additional_user_dn: @@ -31064,6 +31082,12 @@ components: nullable: true description: Optionally verify the LDAP Server's Certificate against the CA Chain in this keypair. + client_certificate: + type: string + format: uuid + nullable: true + description: Client certificate to authenticate against the LDAP Server's + Certificate. bind_cn: type: string bind_password: @@ -31072,6 +31096,9 @@ components: start_tls: type: boolean title: Enable Start TLS + sni: + type: boolean + title: Use Server URI for SNI verification base_dn: type: string minLength: 1 @@ -36356,6 +36383,12 @@ components: nullable: true description: Optionally verify the LDAP Server's Certificate against the CA Chain in this keypair. + client_certificate: + type: string + format: uuid + nullable: true + description: Client certificate to authenticate against the LDAP Server's + Certificate. bind_cn: type: string bind_password: @@ -36364,6 +36397,9 @@ components: start_tls: type: boolean title: Enable Start TLS + sni: + type: boolean + title: Use Server URI for SNI verification base_dn: type: string minLength: 1 diff --git a/web/src/admin/sources/ldap/LDAPSourceForm.ts b/web/src/admin/sources/ldap/LDAPSourceForm.ts index 986a973b1..0985f7cde 100644 --- a/web/src/admin/sources/ldap/LDAPSourceForm.ts +++ b/web/src/admin/sources/ldap/LDAPSourceForm.ts @@ -184,6 +184,26 @@ export class LDAPSourceForm extends ModelForm { ${msg("To use SSL instead, use 'ldaps://' and disable this option.")}

+ + +

+ ${msg("Required for servers using TLS 1.3+")} +

+
{ )}

+ + => { + const args: CryptoCertificatekeypairsListRequest = { + ordering: "name", + hasKey: true, + includeDetails: false, + }; + if (query !== undefined) { + args.search = query; + } + const certificates = await new CryptoApi( + DEFAULT_CONFIG, + ).cryptoCertificatekeypairsList(args); + return certificates.results; + }} + .renderElement=${(item: CertificateKeyPair): string => { + return item.name; + }} + .value=${(item: CertificateKeyPair | undefined): string | undefined => { + return item?.pk; + }} + .selected=${(item: CertificateKeyPair): boolean => { + return item.pk === this.instance?.clientCertificate; + }} + ?blankable=${true} + > + +

+ ${msg( + "Client certificate keypair to authenticate against the LDAP Server's Certificate.", + )} +

+
Certificate Zertifikat - - Due to protocol limitations, this certificate is only used when the outpost has a single provider, or all providers use the same certificate. - - - If multiple providers share an outpost, a self-signed certificate is used. - Wenn sich mehrere Anbieter einen Außenposten teilen, wird ein selbstsigniertes Zertifikat verwendet. - UID start number UID-Startnummer @@ -5722,6 +5715,27 @@ Bindings to groups/users are checked against the user of the event. Activate Aktivieren + + Use Server URI for SNI verification + + + Required for servers using TLS 1.3+ + + + Client certificate keypair to authenticate against the LDAP Server's Certificate. + + + The certificate for the above configured Base DN. As a fallback, the provider uses a self-signed certificate. + + + TLS Server name + + + DNS name for which the above configured certificate should be used. The certificate cannot be detected based on the base DN, as the SSL/TLS negotiation happens before such data is exchanged. + + + TLS Client authentication certificate + diff --git a/web/xliff/en.xlf b/web/xliff/en.xlf index b9cbe7086..37f5aa799 100644 --- a/web/xliff/en.xlf +++ b/web/xliff/en.xlf @@ -777,14 +777,6 @@ Certificate Certificate - - Due to protocol limitations, this certificate is only used when the outpost has a single provider, or all providers use the same certificate. - Due to protocol limitations, this certificate is only used when the outpost has a single provider, or all providers use the same certificate. - - - If multiple providers share an outpost, a self-signed certificate is used. - If multiple providers share an outpost, a self-signed certificate is used. - UID start number UID start number @@ -6039,6 +6031,27 @@ Bindings to groups/users are checked against the user of the event. Activate Activate + + Use Server URI for SNI verification + + + Required for servers using TLS 1.3+ + + + Client certificate keypair to authenticate against the LDAP Server's Certificate. + + + The certificate for the above configured Base DN. As a fallback, the provider uses a self-signed certificate. + + + TLS Server name + + + DNS name for which the above configured certificate should be used. The certificate cannot be detected based on the base DN, as the SSL/TLS negotiation happens before such data is exchanged. + + + TLS Client authentication certificate + diff --git a/web/xliff/es.xlf b/web/xliff/es.xlf index 9c8ff95f2..a7728aae3 100644 --- a/web/xliff/es.xlf +++ b/web/xliff/es.xlf @@ -733,13 +733,6 @@ Certificate Certificado - - Due to protocol limitations, this certificate is only used when the outpost has a single provider, or all providers use the same certificate. - - - If multiple providers share an outpost, a self-signed certificate is used. - Si varios proveedores comparten un puesto avanzado, se utiliza un certificado autofirmado. - UID start number Número inicial de UID @@ -5630,6 +5623,27 @@ Bindings to groups/users are checked against the user of the event. Activate Activar + + Use Server URI for SNI verification + + + Required for servers using TLS 1.3+ + + + Client certificate keypair to authenticate against the LDAP Server's Certificate. + + + The certificate for the above configured Base DN. As a fallback, the provider uses a self-signed certificate. + + + TLS Server name + + + DNS name for which the above configured certificate should be used. The certificate cannot be detected based on the base DN, as the SSL/TLS negotiation happens before such data is exchanged. + + + TLS Client authentication certificate + diff --git a/web/xliff/fr_FR.xlf b/web/xliff/fr_FR.xlf index 0a0749c7f..e3bba1891 100644 --- a/web/xliff/fr_FR.xlf +++ b/web/xliff/fr_FR.xlf @@ -749,13 +749,6 @@ Certificate Certificat - - Due to protocol limitations, this certificate is only used when the outpost has a single provider, or all providers use the same certificate. - - - If multiple providers share an outpost, a self-signed certificate is used. - Si plusieurs fournisseurs partagent un avant-poste, un certificat auto-signé est utilisé. - UID start number Numéro de départ d'UID @@ -5737,6 +5730,27 @@ Bindings to groups/users are checked against the user of the event. Activate Activer + + Use Server URI for SNI verification + + + Required for servers using TLS 1.3+ + + + Client certificate keypair to authenticate against the LDAP Server's Certificate. + + + The certificate for the above configured Base DN. As a fallback, the provider uses a self-signed certificate. + + + TLS Server name + + + DNS name for which the above configured certificate should be used. The certificate cannot be detected based on the base DN, as the SSL/TLS negotiation happens before such data is exchanged. + + + TLS Client authentication certificate + diff --git a/web/xliff/pl.xlf b/web/xliff/pl.xlf index 16e0d4537..a4c7bfe04 100644 --- a/web/xliff/pl.xlf +++ b/web/xliff/pl.xlf @@ -752,13 +752,6 @@ Certificate Certyfikat - - Due to protocol limitations, this certificate is only used when the outpost has a single provider, or all providers use the same certificate. - - - If multiple providers share an outpost, a self-signed certificate is used. - Jeśli wielu dostawców współdzieli placówkę, używany jest certyfikat z podpisem własnym. - UID start number Numer początkowy UID @@ -5869,6 +5862,27 @@ Bindings to groups/users are checked against the user of the event. Activate Aktywuj + + Use Server URI for SNI verification + + + Required for servers using TLS 1.3+ + + + Client certificate keypair to authenticate against the LDAP Server's Certificate. + + + The certificate for the above configured Base DN. As a fallback, the provider uses a self-signed certificate. + + + TLS Server name + + + DNS name for which the above configured certificate should be used. The certificate cannot be detected based on the base DN, as the SSL/TLS negotiation happens before such data is exchanged. + + + TLS Client authentication certificate + diff --git a/web/xliff/pseudo-LOCALE.xlf b/web/xliff/pseudo-LOCALE.xlf index 7e315cdec..017d57a3a 100644 --- a/web/xliff/pseudo-LOCALE.xlf +++ b/web/xliff/pseudo-LOCALE.xlf @@ -761,14 +761,6 @@ Certificate - - - Due to protocol limitations, this certificate is only used when the outpost has a single provider, or all providers use the same certificate. - - - - If multiple providers share an outpost, a self-signed certificate is used. - UID start number @@ -5973,6 +5965,27 @@ Bindings to groups/users are checked against the user of the event. Activate + + + Use Server URI for SNI verification + + + Required for servers using TLS 1.3+ + + + Client certificate keypair to authenticate against the LDAP Server's Certificate. + + + The certificate for the above configured Base DN. As a fallback, the provider uses a self-signed certificate. + + + TLS Server name + + + DNS name for which the above configured certificate should be used. The certificate cannot be detected based on the base DN, as the SSL/TLS negotiation happens before such data is exchanged. + + + TLS Client authentication certificate diff --git a/web/xliff/tr.xlf b/web/xliff/tr.xlf index 0cb41745c..4e6ae5aeb 100644 --- a/web/xliff/tr.xlf +++ b/web/xliff/tr.xlf @@ -733,13 +733,6 @@ Certificate Sertifika - - Due to protocol limitations, this certificate is only used when the outpost has a single provider, or all providers use the same certificate. - - - If multiple providers share an outpost, a self-signed certificate is used. - Birden çok sağlayıcı bir üssü paylaşıyorsa, otomatik olarak imzalanan bir sertifika kullanılır. - UID start number UID başlangıç numarası @@ -5620,6 +5613,27 @@ Bindings to groups/users are checked against the user of the event. Activate Etkinleştir + + Use Server URI for SNI verification + + + Required for servers using TLS 1.3+ + + + Client certificate keypair to authenticate against the LDAP Server's Certificate. + + + The certificate for the above configured Base DN. As a fallback, the provider uses a self-signed certificate. + + + TLS Server name + + + DNS name for which the above configured certificate should be used. The certificate cannot be detected based on the base DN, as the SSL/TLS negotiation happens before such data is exchanged. + + + TLS Client authentication certificate + diff --git a/web/xliff/zh-Hans.xlf b/web/xliff/zh-Hans.xlf index 861c8b067..f50358a42 100644 --- a/web/xliff/zh-Hans.xlf +++ b/web/xliff/zh-Hans.xlf @@ -965,16 +965,6 @@ Certificate 证书 - - - Due to protocol limitations, this certificate is only used when the outpost has a single provider, or all providers use the same certificate. - 由于协议限制,只在前哨有单个提供程序,或所有提供程序都使用相同证书时才使用此证书。 - - - - If multiple providers share an outpost, a self-signed certificate is used. - 如果多个提供程序共享同一个前哨,则使用自签名证书。 - UID start number @@ -7547,6 +7537,27 @@ Bindings to groups/users are checked against the user of the event. 激活 + + Use Server URI for SNI verification + + + Required for servers using TLS 1.3+ + + + Client certificate keypair to authenticate against the LDAP Server's Certificate. + + + The certificate for the above configured Base DN. As a fallback, the provider uses a self-signed certificate. + + + TLS Server name + + + DNS name for which the above configured certificate should be used. The certificate cannot be detected based on the base DN, as the SSL/TLS negotiation happens before such data is exchanged. + + + TLS Client authentication certificate + diff --git a/web/xliff/zh-Hant.xlf b/web/xliff/zh-Hant.xlf index aab8e7994..a12a5e055 100644 --- a/web/xliff/zh-Hant.xlf +++ b/web/xliff/zh-Hant.xlf @@ -740,13 +740,6 @@ Certificate 证书 - - Due to protocol limitations, this certificate is only used when the outpost has a single provider, or all providers use the same certificate. - - - If multiple providers share an outpost, a self-signed certificate is used. - 如果多个提供商共享一个 Outpost,则使用自签名证书。 - UID start number UID 起始编号 @@ -5675,6 +5668,27 @@ Bindings to groups/users are checked against the user of the event. Activate 启用 + + Use Server URI for SNI verification + + + Required for servers using TLS 1.3+ + + + Client certificate keypair to authenticate against the LDAP Server's Certificate. + + + The certificate for the above configured Base DN. As a fallback, the provider uses a self-signed certificate. + + + TLS Server name + + + DNS name for which the above configured certificate should be used. The certificate cannot be detected based on the base DN, as the SSL/TLS negotiation happens before such data is exchanged. + + + TLS Client authentication certificate + diff --git a/web/xliff/zh_TW.xlf b/web/xliff/zh_TW.xlf index 3ba0aee41..840a00c89 100644 --- a/web/xliff/zh_TW.xlf +++ b/web/xliff/zh_TW.xlf @@ -740,13 +740,6 @@ Certificate 证书 - - Due to protocol limitations, this certificate is only used when the outpost has a single provider, or all providers use the same certificate. - - - If multiple providers share an outpost, a self-signed certificate is used. - 如果多个提供商共享一个 Outpost,则使用自签名证书。 - UID start number UID 起始编号 @@ -5674,6 +5667,27 @@ Bindings to groups/users are checked against the user of the event. Activate 启用 + + Use Server URI for SNI verification + + + Required for servers using TLS 1.3+ + + + Client certificate keypair to authenticate against the LDAP Server's Certificate. + + + The certificate for the above configured Base DN. As a fallback, the provider uses a self-signed certificate. + + + TLS Server name + + + DNS name for which the above configured certificate should be used. The certificate cannot be detected based on the base DN, as the SSL/TLS negotiation happens before such data is exchanged. + + + TLS Client authentication certificate +