goauthentik / authentik

The authentication glue you need.
https://goauthentik.io
Other
13.53k stars 905 forks source link

LDAP Source URI is parsed incorrectly which leads to invalid SNI configuration #7756

Open jgraichen opened 11 months ago

jgraichen commented 11 months ago

Describe the bug

I am testing Authentik with LDAP federation using a TLS-only openLDAP. The LDAP server runs on Debian Bookworm with a normal TLS setup, a valid LE cert, TLS 1.2+, etc.

The Authentik 2023.10.4 image fails to connect to that LDAP error and instead logs an SSL error. The LDAP server reports a TLS negotiation failure.

The wire trace indicates a TLS v1.0 connection failure.

To Reproduce

  1. Set up LDAP federation with an openLDAP server over LDAPS.
  2. Manually run LDAP sync.
  3. Nothing visually happens, but an error is logged in the worker.

Expected behavior

Connect to LDAP server over TLS and sync users and groups.

Logs

Error logged in worker:

{
  "event": "Task authentik.sources.ldap.tasks.ldap_sync_single[f90970f7-1710-4c07-9435-b205cbb9068a] raised unexpected: LDAPSocketOpenError(\"('socket ssl wrapping error: [SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1006)',)\")",
  "exception": [
    {
      "exc_type": "Exception",
      "exc_value": "('socket ssl wrapping error: [SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1006)',)",
      "frames": [
        {
          "filename": "/usr/local/lib/python3.11/site-packages/celery/app/trace.py",
          "line": "",
          "lineno": 477,
          "locals": {},
          "name": "trace_task"
        },
        {
          "filename": "/usr/local/lib/python3.11/site-packages/celery/app/trace.py",
          "line": "",
          "lineno": 760,
          "locals": {},
          "name": "__protected_call__"
        },
        {
          "filename": "/authentik/sources/ldap/tasks.py",
          "line": "",
          "lineno": 51,
          "locals": {},
          "name": "ldap_sync_single"
        },
        {
          "filename": "/authentik/sources/ldap/tasks.py",
          "line": "",
          "lineno": 64,
          "locals": {},
          "name": "ldap_sync_paginator"
        },
        {
          "filename": "/authentik/sources/ldap/sync/base.py",
          "line": "",
          "lineno": 30,
          "locals": {},
          "name": "__init__"
        },
        {
          "filename": "/authentik/sources/ldap/models.py",
          "line": "",
          "lineno": 174,
          "locals": {},
          "name": "connection"
        },
        {
          "filename": "/usr/local/lib/python3.11/site-packages/ldap3/core/connection.py",
          "line": "",
          "lineno": 1313,
          "locals": {},
          "name": "start_tls"
        },
        {
          "filename": "/usr/local/lib/python3.11/site-packages/ldap3/strategy/sync.py",
          "line": "",
          "lineno": 57,
          "locals": {},
          "name": "open"
        },
        {
          "filename": "/usr/local/lib/python3.11/site-packages/ldap3/strategy/base.py",
          "line": "",
          "lineno": 146,
          "locals": {},
          "name": "open"
        }
      ],
      "is_cause": false,
      "syntax_error": null
    }
  ],
  "level": "error",
  "logger": "celery.app.trace",
  "timestamp": 1701462020.284353
}

Compose logs:

goauthentik-worker-1      | {"event": "Task failure", "exc": "LDAPSocketOpenError(\"('socket ssl wrapping error: [SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1006)',)\")", "level": "warning", "logger": "authentik.root.celery", "pid": 985, "task_id": "task-f90970f717104c079435b205cbb9068a", "timestamp": "2023-12-01T20:20:20.284100"}
goauthentik-worker-1      | {"event": "Task authentik.sources.ldap.tasks.ldap_sync_single[f90970f7-1710-4c07-9435-b205cbb9068a] raised unexpected: LDAPSocketOpenError(\"('socket ssl wrapping error: [SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1006)',)\")", "exception": [{"exc_type": "Exception", "exc_value": "('socket ssl wrapping error: [SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1006)',)", "frames": [{"filename": "/usr/local/lib/python3.11/site-packages/celery/app/trace.py", "line": "", "lineno": 477, "locals": {}, "name": "trace_task"}, {"filename": "/usr/local/lib/python3.11/site-packages/celery/app/trace.py", "line": "", "lineno": 760, "locals": {}, "name": "__protected_call__"}, {"filename": "/authentik/sources/ldap/tasks.py", "line": "", "lineno": 51, "locals": {}, "name": "ldap_sync_single"}, {"filename": "/authentik/sources/ldap/tasks.py", "line": "", "lineno": 64, "locals": {}, "name": "ldap_sync_paginator"}, {"filename": "/authentik/sources/ldap/sync/base.py", "line": "", "lineno": 30, "locals": {}, "name": "__init__"}, {"filename": "/authentik/sources/ldap/models.py", "line": "", "lineno": 174, "locals": {}, "name": "connection"}, {"filename": "/usr/local/lib/python3.11/site-packages/ldap3/core/connection.py", "line": "", "lineno": 1313, "locals": {}, "name": "start_tls"}, {"filename": "/usr/local/lib/python3.11/site-packages/ldap3/strategy/sync.py", "line": "", "lineno": 57, "locals": {}, "name": "open"}, {"filename": "/usr/local/lib/python3.11/site-packages/ldap3/strategy/base.py", "line": "", "lineno": 146, "locals": {}, "name": "open"}], "is_cause": false, "syntax_error": null}], "level": "error", "logger": "celery.app.trace", "timestamp": 1701462020.284353}
goauthentik-worker-1      | {"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 985, "state": "FAILURE", "task_id": "f90970f717104c079435b205cbb9068a", "task_name": "ldap_sync_single", "timestamp": "2023-12-01T20:20:20.284693"}

Version and Deployment (please complete the following information):

Additional context

slapd.conf:

TLSCertificateFile /etc/acme/openldap/fullchain.pem
TLSCertificateKeyFile /etc/acme/openldap/privkey.pem
TLSCACertificateFile /etc/ssl/certs/ca-certificates.crt
TLSCipherSuite NORMAL:!CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:+CHACHA20-POLY1305:!COMP-ALL:+COMP-NULL

security tls=1 ssf=128

openLDAP log:

Dec 01 20:33:27 ldap slapd[1757597]: conn=1012 fd=20 ACCEPT from IP=10.72.0.217:36935 (IP=0.0.0.0:636)
Dec 01 20:33:27 ldap slapd[1757597]: conn=1012 fd=20 closed (TLS negotiation failure)
Dec 01 20:33:27 ldap slapd[1757597]: conn=1013 fd=20 ACCEPT from IP=10.72.0.217:42083 (IP=0.0.0.0:636)
Dec 01 20:33:27 ldap slapd[1757597]: conn=1013 fd=20 closed (TLS negotiation failure)

testssl of the LDAP server (no issues connecting):

> testssl ldap.example.org:636

No engine or GOST support via engine with your /usr/bin/openssl

###########################################################
    testssl       3.0.7 from https://testssl.sh/

      This program is free software. Distribution and
             modification under GPLv2 permitted.
      USAGE w/o ANY WARRANTY. USE IT AT YOUR OWN RISK!

       Please file bugs @ https://testssl.sh/bugs/

###########################################################

 Using "OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)" [~76 ciphers]
 on broadhead:/usr/bin/openssl
 (built: "Oct 13 12:02:49 2023", platform: "debian-amd64")

 Start 2023-12-01 21:11:19        -->> 10.72.253.38:636 (ldap.example.org) <<--

 rDNS (10.72.253.38):    ldap.example.org.
 Service detected:       Couldn't determine what's running on port 636, assuming no HTTP service => skipping all HTTP checks

 Testing protocols via sockets except NPN+ALPN 

 SSLv2      not offered (OK)
 SSLv3      not offered (OK)
 TLS 1      not offered
 TLS 1.1    not offered
 TLS 1.2    offered (OK)
 TLS 1.3    offered (OK): final
 NPN/SPDY   not offered
 ALPN/HTTP2 not offered

 Testing cipher categories 

 NULL ciphers (no encryption)                  not offered (OK)
 Anonymous NULL Ciphers (no authentication)    not offered (OK)
 Export ciphers (w/o ADH+NULL)                 not offered (OK)
 LOW: 64 Bit + DES, RC[2,4] (w/o export)       not offered (OK)
 Triple DES Ciphers / IDEA                     not offered
 Obsolete CBC ciphers (AES, ARIA etc.)         not offered
 Strong encryption (AEAD ciphers)              offered (OK)

 Testing robust (perfect) forward secrecy, (P)FS -- omitting Null Authentication/Encryption, 3DES, RC4 

 PFS is offered (OK)          TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 TLS_AES_128_GCM_SHA256 ECDHE-ECDSA-AES128-GCM-SHA256 
 Elliptic curves offered:     prime256v1 secp384r1 secp521r1 X25519 X448 
 Finite field group:          ffdhe2048 ffdhe3072 ffdhe4096 ffdhe6144 ffdhe8192

 Testing server preferences 

 Has server cipher order?     no (NOT ok)
 Negotiated protocol          TLSv1.3
 Negotiated cipher            TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519) (limited sense as client will pick)
 Negotiated cipher per proto  (limited sense as client will pick)
     ECDHE-ECDSA-AES256-GCM-SHA384: TLSv1.2
     TLS_AES_256_GCM_SHA384:        TLSv1.3
 No further cipher order check has been done as order is determined by the client

 Testing server defaults (Server Hello) 

 TLS extensions (standard)    "EC point formats/#11" "renegotiation info/#65281" "key share/#51" "supported versions/#43" "extended master secret/#23" "max fragment length/#1"
 Session Ticket RFC 5077 hint no -- no lifetime advertised
 SSL Session ID support       no
 Session Resumption           Tickets no, ID: no
 TLS clock skew               Random values, no fingerprinting possible 
 Signature Algorithm          SHA256 with RSA
 Server key size              EC 256 bits
 Server key usage             Digital Signature
 Server extended key usage    TLS Web Server Authentication, TLS Web Client Authentication
 Serial                       03.................................. (OK: length 18)
 Fingerprints                 SHA1 sha1 2E7.....................................
                              SHA256 sha256 8DD.............................................................
 Common Name (CN)             ldap1.region1.example.org 
 subjectAltName (SAN)         ldap.example.org ldap1.region1.example.org 
 Issuer                       R3 (Let's Encrypt from US)
 Trust (hostname)             Ok via SAN (same w/o SNI)
 Chain of trust               Ok   
 EV cert (experimental)       no 
 ETS/"eTLS", visibility info  not present
 Certificate Validity (UTC)   30 >= 30 days (2023-10-03 04:12 --> 2024-01-01 04:12)
 # of certificates provided   3
 Certificate Revocation List  --
 OCSP URI                     http://r3.o.lencr.org
 OCSP stapling                not offered
 OCSP must staple extension   --
 DNS CAA RR (experimental)    not offered
 Certificate Transparency     yes (certificate extension)

 Testing vulnerabilities 

 Heartbleed (CVE-2014-0160)                not vulnerable (OK), no heartbeat extension
 CCS (CVE-2014-0224)                       not vulnerable (OK)
 Ticketbleed (CVE-2016-9244), experiment.  --   (applicable only for HTTPS)
 ROBOT                                     Server does not support any cipher suites that use RSA key transport
 Secure Renegotiation (RFC 5746)           supported (OK)
 Secure Client-Initiated Renegotiation     VULNERABLE (NOT ok), potential DoS threat
 CRIME, TLS (CVE-2012-4929)                not vulnerable (OK) (not using HTTP anyway)
 POODLE, SSL (CVE-2014-3566)               not vulnerable (OK), no SSLv3 support
 TLS_FALLBACK_SCSV (RFC 7507)              No fallback possible (OK), no protocol below TLS 1.2 offered
 SWEET32 (CVE-2016-2183, CVE-2016-6329)    not vulnerable (OK)
 FREAK (CVE-2015-0204)                     not vulnerable (OK)
 DROWN (CVE-2016-0800, CVE-2016-0703)      not vulnerable on this host and port (OK)
                                           no RSA certificate, thus certificate can't be used with SSLv2 elsewhere
 LOGJAM (CVE-2015-4000), experimental      not vulnerable (OK): no DH EXPORT ciphers, no DH key detected with <= TLS 1.2
 BEAST (CVE-2011-3389)                     not vulnerable (OK), no SSL3 or TLS1
 LUCKY13 (CVE-2013-0169), experimental     not vulnerable (OK)
 RC4 (CVE-2013-2566, CVE-2015-2808)        no RC4 ciphers detected (OK)

 Testing 370 ciphers via OpenSSL plus sockets against the server, ordered by encryption strength 

Hexcode  Cipher Suite Name (OpenSSL)       KeyExch.   Encryption  Bits     Cipher Suite Name (IANA/RFC)
-----------------------------------------------------------------------------------------------------------------------------
 x1302   TLS_AES_256_GCM_SHA384            ECDH 253   AESGCM      256      TLS_AES_256_GCM_SHA384                             
 x1303   TLS_CHACHA20_POLY1305_SHA256      ECDH 253   ChaCha20    256      TLS_CHACHA20_POLY1305_SHA256                       
 xc02c   ECDHE-ECDSA-AES256-GCM-SHA384     ECDH 253   AESGCM      256      TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384            
 xcca9   ECDHE-ECDSA-CHACHA20-POLY1305     ECDH 253   ChaCha20    256      TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256      
 x1301   TLS_AES_128_GCM_SHA256            ECDH 253   AESGCM      128      TLS_AES_128_GCM_SHA256                             
 xc02b   ECDHE-ECDSA-AES128-GCM-SHA256     ECDH 253   AESGCM      128      TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256            

Could not determine the protocol, only simulating generic clients.

 Running client simulations via sockets 

 Android 4.4.2                TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384, 521 bit ECDH (P-521)
 Android 5.0.0                TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256, 521 bit ECDH (P-521)
 Android 6.0                  TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256, 256 bit ECDH (P-256)
 Android 7.0 (native)         TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256, 256 bit ECDH (P-256)
 Android 8.1 (native)         TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256, 253 bit ECDH (X25519)
 Android 9.0 (native)         TLSv1.3 TLS_AES_128_GCM_SHA256, 253 bit ECDH (X25519)
 Android 10.0 (native)        TLSv1.3 TLS_AES_128_GCM_SHA256, 253 bit ECDH (X25519)
 Chrome 74 (Win 10)           TLSv1.3 TLS_AES_128_GCM_SHA256, 253 bit ECDH (X25519)
 Chrome 79 (Win 10)           TLSv1.3 TLS_AES_128_GCM_SHA256, 253 bit ECDH (X25519)
 Firefox 66 (Win 8.1/10)      TLSv1.3 TLS_AES_128_GCM_SHA256, 253 bit ECDH (X25519)
 Firefox 71 (Win 10)          TLSv1.3 TLS_AES_128_GCM_SHA256, 253 bit ECDH (X25519)
 IE 6 XP                      No connection
 IE 8 Win 7                   No connection
 IE 8 XP                      No connection
 IE 11 Win 7                  TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
 IE 11 Win 8.1                TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
 IE 11 Win Phone 8.1          TLSv1.2 ECDHE-ECDSA-AES128-GCM-SHA256, 256 bit ECDH (P-256)
 IE 11 Win 10                 TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
 Edge 15 Win 10               TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
 Edge 17 (Win 10)             TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
 Opera 66 (Win 10)            TLSv1.3 TLS_AES_128_GCM_SHA256, 253 bit ECDH (X25519)
 Safari 9 iOS 9               TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
 Safari 9 OS X 10.11          TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
 Safari 10 OS X 10.12         TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
 Safari 12.1 (iOS 12.2)       TLSv1.3 TLS_CHACHA20_POLY1305_SHA256, 253 bit ECDH (X25519)
 Safari 13.0 (macOS 10.14.6)  TLSv1.3 TLS_CHACHA20_POLY1305_SHA256, 253 bit ECDH (X25519)
 Apple ATS 9 iOS 9            TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
 Java 6u45                    No connection
 Java 7u25                    No connection
 Java 8u161                   TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
 Java 11.0.2 (OpenJDK)        TLSv1.3 TLS_AES_128_GCM_SHA256, 256 bit ECDH (P-256)
 Java 12.0.1 (OpenJDK)        TLSv1.3 TLS_AES_128_GCM_SHA256, 256 bit ECDH (P-256)
 OpenSSL 1.0.2e               TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
 OpenSSL 1.1.0l (Debian)      TLSv1.2 ECDHE-ECDSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
 OpenSSL 1.1.1d (Debian)      TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
 Thunderbird (68.3)           TLSv1.3 TLS_AES_128_GCM_SHA256, 253 bit ECDH (X25519)

 Done 2023-12-01 21:11:58 [  41s] -->> 10.72.253.38:636 (ldap.example.org) <<--

Wireshark recorded TLS failure:

image

BeryJu commented 11 months ago

I can't tell from your issue if you're using starttls or port 636 SSL, either way you might want to try https://goauthentik.io/docs/installation/configuration#authentik_ldap__tls__ciphers to adjust the ciphers, and/or adding the Root CA to authentik, I think by default ldap3 (which is the LDAP library we use) uses the system CA store

Actually on further looking, we don't install ca-certificates in the container which probably doesn't help with this

jgraichen commented 11 months ago

@BeryJu Thank you for looking! I am using direct TLS with LDAPS on port 636.

ca-certificates seems to be installed in the container:

> docker exec -it -u root goauthentik-worker-1 bash -l
root@989bd69f9ec4:/# apt show ca-certificates
Package: ca-certificates
Version: 20230311
Status: install ok installed
Priority: standard
Section: misc
Maintainer: Julien Cristau <jcristau@debian.org>
Installed-Size: 393 kB
Depends: openssl (>= 1.1.1), debconf (>= 0.5) | debconf-2.0
Breaks: ca-certificates-java (<< 20121112+nmu1)
Enhances: openssl
Download-Size: unknown
APT-Manual-Installed: yes
APT-Sources: /var/lib/dpkg/status
Description: Common CA certificates

I further tried debugging using ldapsearch from inside the container (by installing ldap-utils via APT). I didn't get a result yet, but at least TLS seems to work, according to the slapd log:

Dec 03 19:08:20 ldap slapd[1928874]: conn=1011 fd=20 ACCEPT from IP=10.72.0.217:57242 (IP=0.0.0.0:636)
Dec 03 19:08:20 ldap slapd[1928874]: conn=1011 fd=20 TLS established tls_ssf=256 ssf=256 tls_proto=TLS1.3 tls_cipher=AES-256-GCM
Dec 03 19:08:20 ldap slapd[1928874]: conn=1011 fd=20 closed (connection lost)
root@989bd69f9ec4:/# apt update && apt install ldap-utils
[..]
root@989bd69f9ec4:/# ldapsearch -x -H ldaps://ldap1.pdm.aixn.de -b 'o=altimos'
ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)

Therefore, it does not seem to be a fundamental system/TLS issue.

For reference, the same command from the host does work:

> ldapsearch -x -H ldaps://ldap1.pdm.aixn.de:636 -b 'o=altimos' | head -n5
# extended LDIF
#
# LDAPv3
# base <o=altimos> with scope subtree
# filter: (objectclass=*)
jgraichen commented 11 months ago

There are no issues when connecting from a minimal python script inside the authentik worker container to the LDAP server:

authentik@ea28a5d1abf1:~$ python3 /tmp/test.py 
DEBUG:ldap3:ERROR:detail level set to BASIC
DEBUG:ldap3:BASIC:instantiated Tls: <Tls(validate=<VerifyMode.CERT_REQUIRED: 2>)>
DEBUG:ldap3:BASIC:instantiated Server: <Server(host='ldap1.pdm.aixn.de', port=636, use_ssl=True, allowed_referral_hosts=[('*', True)], tls=Tls(validate=<VerifyMode.CERT_REQUIRED: 2>), get_info='ALL', connect_timeout=10, mode='IP_V6_PREFERRED')>
DEBUG:ldap3:BASIC:instantiated <SyncStrategy>: <ldaps://ldap1.pdm.aixn.de:636 - ssl - user: None - not lazy - unbound - closed - <no socket> - tls not started - not listening - No strategy - internal decoder - async - real DSA - not pooled - cannot stream output>
DEBUG:ldap3:BASIC:instantiated Connection: <Connection(server=Server(host='ldap1.pdm.aixn.de', port=636, use_ssl=True, allowed_referral_hosts=[('*', True)], tls=Tls(validate=<VerifyMode.CERT_REQUIRED: 2>), get_info='ALL', connect_timeout=10, mode='IP_V6_PREFERRED'), auto_bind='DEFAULT', version=3, authentication='ANONYMOUS', client_strategy='SYNC', auto_referrals=True, check_names=True, read_only=False, lazy=False, raise_exceptions=False, fast_decoder=True, auto_range=True, return_empty_attributes=True, auto_encode=True, auto_escape=True, use_referral_cache=False)>
DEBUG:ldap3:BASIC:start START TLS operation via <ldaps://ldap1.pdm.aixn.de:636 - ssl - user: None - not lazy - unbound - closed - <no socket> - tls not started - not listening - SyncStrategy - internal decoder>
DEBUG:ldap3:BASIC:address for <ldaps://ldap1.pdm.aixn.de:636 - ssl> resolved as <[<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('10.72.0.16', 636)]>
DEBUG:ldap3:BASIC:obtained candidate address for <ldaps://ldap1.pdm.aixn.de:636 - ssl>: <[<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('10.72.0.16', 636)]> with mode IP_V6_PREFERRED
DEBUG:ldap3:BASIC:try to open candidate address [<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('10.72.0.16', 636)]
DEBUG:ldap3:BASIC:refreshing server info for <ldaps://ldap1.pdm.aixn.de:636 - ssl - user: None - not lazy - unbound - open - <local: 172.25.0.2:52601 - remote: 10.72.0.16:636> - tls not started - listening - SyncStrategy - internal decoder>
DEBUG:ldap3:BASIC:start SEARCH operation via <ldaps://ldap1.pdm.aixn.de:636 - ssl - user: None - not lazy - unbound - open - <local: 172.25.0.2:52601 - remote: 10.72.0.16:636> - tls not started - listening - SyncStrategy - internal decoder>
DEBUG:ldap3:BASIC:done SEARCH operation, result <True>
DEBUG:ldap3:BASIC:DSA info read for <ldaps://ldap1.pdm.aixn.de:636 - ssl> via <ldaps://ldap1.pdm.aixn.de:636 - ssl - user: None - not lazy - unbound - open - <local: 172.25.0.2:52601 - remote: 10.72.0.16:636> - tls not started - listening - SyncStrategy - internal decoder>
DEBUG:ldap3:BASIC:start SEARCH operation via <ldaps://ldap1.pdm.aixn.de:636 - ssl - user: None - not lazy - unbound - open - <local: 172.25.0.2:52601 - remote: 10.72.0.16:636> - tls not started - listening - SyncStrategy - internal decoder>
DEBUG:ldap3:BASIC:done SEARCH operation, result <True>
DEBUG:ldap3:BASIC:schema read for <ldaps://ldap1.pdm.aixn.de:636 - ssl> via <ldaps://ldap1.pdm.aixn.de:636 - ssl - user: None - not lazy - unbound - open - <local: 172.25.0.2:52601 - remote: 10.72.0.16:636> - tls not started - listening - SyncStrategy - internal decoder>
DEBUG:ldap3:BASIC:done START TLS operation, result <False>
DEBUG:ldap3:BASIC:start SEARCH operation via <ldaps://ldap1.pdm.aixn.de:636 - ssl - user: None - not lazy - unbound - open - <local: 172.25.0.2:52601 - remote: 10.72.0.16:636> - tls not started - listening - SyncStrategy - internal decoder>
DEBUG:ldap3:BASIC:done SEARCH operation, result <False>

Test script:

import logging
import ssl

from ldap3 import ALL, Connection, Server, Tls
from ldap3.utils.log import BASIC, set_library_log_detail_level

logging.basicConfig(level=logging.DEBUG)
set_library_log_detail_level(BASIC)

tls = Tls(validate=ssl.CERT_REQUIRED)

server = Server(
    "ldaps://ldap1.pdm.aixn.de",
    get_info=ALL,
    connect_timeout=10,
    tls=tls,
)
conn = Connection(server)
conn.start_tls(read_server_info=False)

conn.search(
    search_base="o=altimos",
    search_filter="(objectClass=inetOrgPerson)",
)

The issue seems to be inside the authentik source and how ldap3 is configured/called/used.

jgraichen commented 11 months ago

either way you might want to try goauthentik.io/docs/installation/configuration#authentik_ldaptlsciphers to adjust the ciphers, and/or adding the Root CA to authentik, I think by default ldap3 (which is the LDAP library we use) uses the system CA store

Changing AUTHENTIK_LDAP__TLS__CIPHERS has no effect at all, and the connection from inside the container does work as shown by the test script. There seems to be issues with authentik and how it configures/uses ldap3 inside the worker.

authentik-automation[bot] commented 9 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

jgraichen commented 9 months ago

@BeryJu The issue is still present, and as shown with the standalone test script, directly related to authentik only. The standalone script can successfully connect to a modern, secured LDAP even when run inside the container. Therefore, it cannot be an issue with Python, openSSL, or the network.

Tested again with 2023.10.7, the issue is still present:

{
  "event": "Task authentik.sources.ldap.tasks.ldap_sync_single[fe33cefe-e1d4-44e8-9930-9b2225a46db2] raised unexpected: LDAPSocketOpenError(\"('socket ssl wrapping error: [SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1006)',)\")",
  "exception": [
    {
      "exc_type": "Exception",
      "exc_value": "('socket ssl wrapping error: [SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1006)',)",
      "frames": [
        {
          "filename": "/ak-root/venv/lib/python3.11/site-packages/celery/app/trace.py",
          "line": "",
          "lineno": 477,
          "locals": {},
          "name": "trace_task"
        },
        {
          "filename": "/ak-root/venv/lib/python3.11/site-packages/celery/app/trace.py",
          "line": "",
          "lineno": 760,
          "locals": {},
          "name": "__protected_call__"
        },
        {
          "filename": "/authentik/sources/ldap/tasks.py",
          "line": "",
          "lineno": 59,
          "locals": {},
          "name": "ldap_sync_single"
        },
        {
          "filename": "/authentik/sources/ldap/tasks.py",
          "line": "",
          "lineno": 76,
          "locals": {},
          "name": "ldap_sync_paginator"
        },
        {
          "filename": "/authentik/sources/ldap/sync/base.py",
          "line": "",
          "lineno": 30,
          "locals": {},
          "name": "__init__"
        },
        {
          "filename": "/authentik/sources/ldap/models.py",
          "line": "",
          "lineno": 176,
          "locals": {},
          "name": "connection"
        },
        {
          "filename": "/ak-root/venv/lib/python3.11/site-packages/ldap3/core/connection.py",
          "line": "",
          "lineno": 589,
          "locals": {},
          "name": "bind"
        },
        {
          "filename": "/ak-root/venv/lib/python3.11/site-packages/ldap3/strategy/sync.py",
          "line": "",
          "lineno": 57,
          "locals": {},
          "name": "open"
        },
        {
          "filename": "/ak-root/venv/lib/python3.11/site-packages/ldap3/strategy/base.py",
          "line": "",
          "lineno": 146,
          "locals": {},
          "name": "open"
        }
      ],
      "is_cause": false,
      "syntax_error": null
    }
  ],
  "level": "error",
  "logger": "celery.app.trace",
  "timestamp": 1707382656.7532616
}
jgraichen commented 8 months ago

Tested with 2024.2:

{
  "event": "Task authentik.sources.ldap.tasks.ldap_sync_single[b870f9f2-6216-4e0a-8683-e62009243a39] raised unexpected: LDAPSocketOpenError(\"('socket ssl wrapping error: [SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1000)',)\")",
  "exception": [
    {
      "exc_type": "Exception",
      "exc_value": "('socket ssl wrapping error: [SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol (_ssl.c:1000)',)",
      "frames": [
        {
          "filename": "/ak-root/venv/lib/python3.12/site-packages/celery/app/trace.py",
          "line": "",
          "lineno": 477,
          "locals": {},
          "name": "trace_task"
        },
        {
          "filename": "/ak-root/venv/lib/python3.12/site-packages/celery/app/trace.py",
          "line": "",
          "lineno": 760,
          "locals": {},
          "name": "__protected_call__"
        },
        {
          "filename": "/authentik/sources/ldap/tasks.py",
          "line": "",
          "lineno": 78,
          "locals": {},
          "name": "ldap_sync_single"
        },
        {
          "filename": "/authentik/sources/ldap/tasks.py",
          "line": "",
          "lineno": 95,
          "locals": {},
          "name": "ldap_sync_paginator"
        },
        {
          "filename": "/authentik/sources/ldap/sync/base.py",
          "line": "",
          "lineno": 40,
          "locals": {},
          "name": "__init__"
        },
        {
          "filename": "/authentik/sources/ldap/models.py",
          "line": "",
          "lineno": 184,
          "locals": {},
          "name": "connection"
        },
        {
          "filename": "/ak-root/venv/lib/python3.12/site-packages/ldap3/core/connection.py",
          "line": "",
          "lineno": 589,
          "locals": {},
          "name": "bind"
        },
        {
          "filename": "/ak-root/venv/lib/python3.12/site-packages/ldap3/strategy/sync.py",
          "line": "",
          "lineno": 57,
          "locals": {},
          "name": "open"
        },
        {
          "filename": "/ak-root/venv/lib/python3.12/site-packages/ldap3/strategy/base.py",
          "line": "",
          "lineno": 146,
          "locals": {},
          "name": "open"
        }
      ],
      "is_cause": false,
      "syntax_error": null
    }
  ],
  "level": "error",
  "logger": "celery.app.trace",
  "timestamp": 1709202541.6433022
}
jgraichen commented 8 months ago

Disabling the SNI option works (on main branch). The reason for that is, when giving an ldaps://server address, the code fails to extract a correct SNI:

        # authentik/sources/ldap/models.py:149
        if self.sni:
            tls_kwargs["sni"] = self.server_uri.split(",", maxsplit=1)[0].strip()

The tls_kwargs ends up with {'sni': 'ldaps://server'}.

The code might need to parse whatever is given with e.g. urllib.parse and take either netloc or path:

>>> urlparse("server")
ParseResult(scheme='', netloc='', path='server', params='', query='', fragment='')
>>> urlparse("ldap://server")
ParseResult(scheme='ldap', netloc='server', path='', params='', query='', fragment='')
>>> urlparse("ldaps://server")
ParseResult(scheme='ldaps', netloc='server', path='', params='', query='', fragment='')

Regarding the discussion about ca-certificates: There appears to be no way at all to have the server certificate be verified with the system CA certs. Either no validation mode is set (defaulting to ssl.CERT_NONE) or a peer certificate must be specified:

        if self.peer_certificate:
            tls_kwargs["ca_certs_data"] = self.peer_certificate.certificate_data
            tls_kwargs["validate"] = CERT_REQUIRED

This does match the description in the UI:

image

Yet, not a very secure way ;)

--

Note: Running poetry run ak server fails unless I manually export TMPDIR env to a writable path:

.../authentik/lifecycle/ak: line 49: /authentik-mode: Permission denied
jgraichen commented 8 months ago

@BeryJu I am working on a fix for SNI, but how is it expected to work with multiple LDAP servers?

To what should e.g. ldaps://a,b,c be expanded?

Should ldaps://a,b,c:636 work at all?

authentik-automation[bot] commented 6 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

jgraichen commented 6 months ago

The issue that full URLs are passed to SNI is still present at https://github.com/goauthentik/authentik/blob/main/authentik/sources/ldap/models.py#L151?

authentik-automation[bot] commented 4 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

jgraichen commented 4 months ago

The code appears to still pass the full URL, including protocol and port as the SNI host, and will pass the first host in the list to all connections:

https://github.com/goauthentik/authentik/blob/main/authentik/sources/ldap/models.py#L155