sources/ldap: add optional tls verification certificate

closes #1875

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-12-03 10:09:13 +01:00
parent 99c62af89e
commit f1b9021e3e
8 changed files with 141 additions and 20 deletions

View File

@ -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",

View File

@ -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",
),
),
]

View File

@ -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

View File

@ -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:

View File

@ -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."

View File

@ -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."

View File

@ -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 ""

View File

@ -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<LDAPSource, string> {
${t`To use SSL instead, use 'ldaps://' and disable this option.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`TLS Verification Certificate`}
name="peerCertificate"
>
<select class="pf-c-form-control">
<option
value=""
?selected=${this.instance?.peerCertificate === undefined}
>
---------
</option>
${until(
new CryptoApi(DEFAULT_CONFIG)
.cryptoCertificatekeypairsList({
ordering: "name",
})
.then((keys) => {
return keys.results.map((key) => {
let selected =
this.instance?.peerCertificate === key.pk;
if (keys.results.length === 1) {
selected = true;
}
return html`<option
value=${ifDefined(key.pk)}
?selected=${selected}
>
${key.name}
</option>`;
});
}),
html`<option>${t`Loading...`}</option>`,
)}
</select>
<p class="pf-c-form__helper-text">
${t`When connecting to an LDAP Server with TLS, certificates are not checked by default. Specify a keypair to validate the remote certificate.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Bind CN`} name="bindCn">
<input
type="text"