BookStack icon indicating copy to clipboard operation
BookStack copied to clipboard

can't login with LDAPS on AD without LDAP_TLS_INSECURE=true

Open eoli3n opened this issue 2 years ago • 18 comments

Describe the Bug

I configured BookStack to login with LDAPS on Active Directory, with a certificate produced by a self-signed certificate autority. The certificate autority is available on the host system, but I can't log in, without setting LDAP_TLS_INSECURE=true.

Steps to Reproduce

  1. Configure ldap auth like
AUTH_METHOD=ldap
LDAP_SERVER=ldaps://server.domain.com:636
LDAP_BASE_DN="dc=***,dc=***"
LDAP_DN="cn=bind_dn,cn=users,dc=***,dc=***"
LDAP_PASS="******************************"

LDAP_USER_FILTER=(&(sAMAccountName=${user}))
LDAP_VERSION=3
LDAP_ID_ATTRIBUTE=BIN;objectGUID

LDAP_EMAIL_ATTRIBUTE=mail
LDAP_START_TLS=false
LDAP_TLS_INSECURE=false
  1. Add the certificate autority system wide for Debian 11
cp ca.crt /usr/local/share/ca-certificates/
update-ca-certificates
  1. Validate that the ca is present See https://unix.stackexchange.com/questions/97244/list-all-available-ssl-ca-certificates
$ awk -v cmd='openssl x509 -noout -subject' ' /BEGIN/{close(cmd)};{print | cmd}' < /etc/ssl/certs/ca-certificates.crt | grep FSI
subject=emailAddress = *****************, O = ****************, L = *********, C = **, CN = FSI DI Root CA
  1. Try to authenticate : it fails
  2. Change LDAP_TLS_INSECURE to true
  3. Try to authenticate : it succeed

Expected Behaviour

Log in successful with LDAP_TLS_INSECURE=false

Screenshots or Additional Context

APP_DEBUG log

ErrorException
ldap_bind(): Unable to bind to server: Can't contact LDAP server

PHP Version: 8.2.3
BookStack Version: v23.02

#0 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php(266): Illuminate\Foundation\Bootstrap\HandleExceptions->handleError()
#1 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->Illuminate\Foundation\Bootstrap\{closure}()
#2 /var/www/bookstack/app/Auth/Access/Ldap.php(107): ldap_bind()
#3 /var/www/bookstack/app/Auth/Access/LdapService.php(186): BookStack\Auth\Access\Ldap->bind()
#4 /var/www/bookstack/app/Auth/Access/LdapService.php(58): BookStack\Auth\Access\LdapService->bindSystemUser()
#5 /var/www/bookstack/app/Auth/Access/LdapService.php(94): BookStack\Auth\Access\LdapService->getUserWithAttributes()
#6 /var/www/bookstack/app/Auth/Access/Guards/LdapSessionGuard.php(72): BookStack\Auth\Access\LdapService->getUserDetails()
#7 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php(340): BookStack\Auth\Access\Guards\LdapSessionGuard->attempt()
#8 /var/www/bookstack/app/Auth/Access/LoginService.php(157): Illuminate\Auth\AuthManager->__call()
#9 /var/www/bookstack/app/Http/Controllers/Auth/LoginController.php(148): BookStack\Auth\Access\LoginService->attempt()
#10 /var/www/bookstack/app/Http/Controllers/Auth/LoginController.php(82): BookStack\Http\Controllers\Auth\LoginController->attemptLogin()
#11 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): BookStack\Http\Controllers\Auth\LoginController->login()
#12 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(43): Illuminate\Routing\Controller->callAction()
#13 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Routing/Route.php(259): Illuminate\Routing\ControllerDispatcher->dispatch()
#14 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Routing/Route.php(205): Illuminate\Routing\Route->runController()
#15 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Routing/Router.php(798): Illuminate\Routing\Route->run()
#16 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\Routing\Router->Illuminate\Routing\{closure}()
#17 /var/www/bookstack/app/Http/Middleware/CheckGuard.php(27): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#18 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\CheckGuard->handle()
#19 /var/www/bookstack/app/Http/Middleware/RedirectIfAuthenticated.php(31): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#20 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\RedirectIfAuthenticated->handle()
#21 /var/www/bookstack/app/Http/Middleware/Localization.php(45): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#22 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\Localization->handle()
#23 /var/www/bookstack/app/Http/Middleware/RunThemeActions.php(26): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#24 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\RunThemeActions->handle()
#25 /var/www/bookstack/app/Http/Middleware/CheckEmailConfirmed.php(47): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#26 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\CheckEmailConfirmed->handle()
#27 /var/www/bookstack/app/Http/Middleware/PreventAuthenticatedResponseCaching.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#28 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\PreventAuthenticatedResponseCaching->handle()
#29 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(78): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#30 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\Foundation\Http\Middleware\VerifyCsrfToken->handle()
#31 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#32 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\View\Middleware\ShareErrorsFromSession->handle()
#33 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(121): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#34 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(64): Illuminate\Session\Middleware\StartSession->handleStatefulRequest()
#35 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\Session\Middleware\StartSession->handle()
#36 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#37 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse->handle()
#38 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(67): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#39 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\Cookie\Middleware\EncryptCookies->handle()
#40 /var/www/bookstack/app/Http/Middleware/ApplyCspRules.php(33): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#41 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\ApplyCspRules->handle()
#42 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#43 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Routing/Router.php(797): Illuminate\Pipeline\Pipeline->then()
#44 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Routing/Router.php(776): Illuminate\Routing\Router->runRouteWithinStack()
#45 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Routing/Router.php(740): Illuminate\Routing\Router->runRoute()
#46 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Routing/Router.php(729): Illuminate\Routing\Router->dispatchToRoute()
#47 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(190): Illuminate\Routing\Router->dispatch()
#48 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http\{closure}()
#49 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php(39): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#50 /var/www/bookstack/app/Http/Middleware/TrustProxies.php(41): Illuminate\Http\Middleware\TrustProxies->handle()
#51 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): BookStack\Http\Middleware\TrustProxies->handle()
#52 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#53 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle()
#54 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\Foundation\Http\Middleware\TrimStrings->handle()
#55 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#56 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\Foundation\Http\Middleware\ValidatePostSize->handle()
#57 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(86): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#58 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance->handle()
#59 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
#60 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(165): Illuminate\Pipeline\Pipeline->then()
#61 /var/www/bookstack/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(134): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter()
#62 /var/www/bookstack/public/index.php(52): Illuminate\Foundation\Http\Kernel->handle()
#63 {main}

Browser Details

Firefox on Linux 109.0.1

Exact BookStack Version

v23.01.1

PHP Version

8.2

Hosting Environment

Debian 11 up to date Mariadb Nginx with php8.2-fpm

eoli3n avatar Feb 28 '23 07:02 eoli3n

I tried to configure php8.2-fpm as In /etc/php/8.2/fpm/php.ini

[curl]
; A default value for the CURLOPT_CAINFO option. This is required to be an
; absolute path.
curl.cainfo=/usr/local/share/ca-certificates/ca.crt

[openssl]
; The location of a Certificate Authority (CA) file on the local filesystem
; to use when verifying the identity of SSL/TLS peers. Most users should
; not specify a value for this directive as PHP will attempt to use the
; OS-managed cert stores in its absence. If specified, this value may still
; be overridden on a per-stream basis via the "cafile" SSL stream context
; option.
openssl.cafile=/usr/local/share/ca-certificates/ca.crt

But it changed nothing

eoli3n avatar Feb 28 '23 07:02 eoli3n

Reading https://github.com/BookStackApp/BookStack/issues/1922 didn't help

eoli3n avatar Feb 28 '23 08:02 eoli3n

It seems that the server certificate miss a SAN, so maybe the issue is not related to BookStack. I'll update this ASAP.

eoli3n avatar Feb 28 '23 09:02 eoli3n

Just something else to consider, are you sure you want to use ldaps? From what I understand, that is very old and somewhat outdated and it's more common to be using LDAP over tls (Over the default 389 port, using LDAP_START_TLS=true in the context of BookStack).

ssddanbrown avatar Feb 28 '23 11:02 ssddanbrown

We fixed the problem with the missing SAN, other services run with verified LDAPS. But BookStack still have problem to authenticate with LDAPS.

We are switching to LDAPS, and port 389 will be at some point closed.

eoli3n avatar Feb 28 '23 11:02 eoli3n

Just to confirm, have you restarted both nginx and php-fpm since updating the certs? Might also be worth restarting the system to ensure they're fully picked up.

Alternatively, you could try interacting with the /etc/openldap/ldap.conf file directly, in particular the TLS_CACERT and TLS_CACERTDIR options as detailed here: https://www.openldap.org/software//man.cgi?query=ldap.conf&sektion=5&apropos=0&manpath=OpenLDAP+2.4-Release

ssddanbrown avatar Mar 01 '23 15:03 ssddanbrown

Just to confirm, have you restarted both nginx and php-fpm

Yes, I restarted both at each test.

Alternatively, you could try interacting with the /etc/openldap/ldap.conf file directly

Is bookstack using system wide ldap client ? I don't have any installed for now, and it works. So I guess that php8.2-ldap use its own way to connect ?

eoli3n avatar Mar 01 '23 17:03 eoli3n

From what I can tell, the LDAP extension of PHP uses, and is compiled against, client libraries that handle LDAP abilities. In most cases this is OpenLDAP, and therefore certain configuration can be altered via openldap config. I have not tested this though.

I did just access one of my ubuntu systems and noticed this config file is actually at /etc/ldap/ldap.conf (My earlier example was from my Fedora system) and this already had a pre-set TLS_CACERT option/location.

ssddanbrown avatar Mar 01 '23 17:03 ssddanbrown

As I run Debian, I'll check which package holds that file, I don't have it by default. I keep you updated soon.

eoli3n avatar Mar 01 '23 17:03 eoli3n

I have the same issue as yours. i'm using AD LDAPs for other apps as well. it works just fine. until now, don't find any solution yet. it will only work with [LDAP_TLS_INSECURE=true]. was wondering how we can set up TLS since ldaps is old...

jasonyunliang avatar Apr 09 '23 13:04 jasonyunliang

I'm using BookStack v23.02.2 on Debian 11 with PHP 8.2 using the sury.org repo. LDAPS works perfectly fine for me.

My ldap config:

AUTH_METHOD=ldap
LDAP_SERVER="ldaps://dc01.domain.tld:636 ldaps://dc02.domain.tld:636"
LDAP_BASE_DN=ou=domain-user,dc=domain,dc=tld
LDAP_DN=cn=ldapreader,ou=domain-user,dc=domain,dc=tld
LDAP_PASS=***
LDAP_USER_FILTER=(&(objectClass=user)(sAMAccountName=${user})(memberOf:1.2.840.113556.1.4.1941:=CN=bookstack,OU=permissions,OU=domain-groups,DC=domain,DC=tld)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))
LDAP_VERSION=3
LDAP_EMAIL_ATTRIBUTE=mail
LDAP_DISPLAY_NAME_ATTRIBUTE=cn
LDAP_ID_ATTRIBUTE=BIN;objectGUID
LDAP_USER_TO_GROUPS=true
LDAP_GROUP_ATTRIBUTE="memberOf"
LDAP_REMOVE_FROM_GROUPS=true
LDAP_START_TLS=false
LDAP_TLS_INSECURE=false

I activated my internal CA certificates on debian using the command dpkg-reconfigure ca-certificates but I don't know if that makes any difference. Are you really sure that the domain controller is using the right certificate? AD DS is a bit odd when multiple suitable certificates are present in the cert store. It does not use the newest (latest starting date) cert, it always uses the one with the largest lifetime (expiration date the furthest in future). You don't need to restart anything on the domain controller, the moment a better (longer lifetime) certificate is available it immediately starts using it.

drie-cdts avatar Apr 14 '23 12:04 drie-cdts

i'm using rocky linux with docker-compose to set up bookstack. where should i import the DC CA to ? on the linux host /etc/pki/tls ? let me try that out. and will update later.

jasonyunliang avatar Apr 17 '23 02:04 jasonyunliang

i didn't import the certificate, but directly change the settings below.

AUTH_METHOD=ldap LDAP_SERVER=ldap://server.domain.com:389 LDAP_BASE_DN="dc=,dc=" LDAP_DN="cn=bind_dn,cn=users,dc=,dc=" LDAP_PASS="******************************"

LDAP_USER_FILTER=(&(sAMAccountName=${user})) LDAP_VERSION=3 LDAP_ID_ATTRIBUTE=BIN;objectGUID

LDAP_EMAIL_ATTRIBUTE=mail LDAP_START_TLS=true LDAP_TLS_INSECURE=false

But everytime i login to the system , it has to go twice . and the first time showed " An unknown error occured , xxx " . and the second time can successfully sign in. it's very strange. dont know why.

jasonyunliang avatar Apr 17 '23 09:04 jasonyunliang

@jasonyunliang If you're running bookstack in a docker container, you'll need to be doing any certificate stuff within the container itself, rather than the host.

and the first time showed " An unknown error occured , xxx "

BookStack will log detail upon this error to its error log file as described here: https://www.bookstackapp.com/docs/admin/debugging/

ssddanbrown avatar Apr 17 '23 15:04 ssddanbrown

@ssddanbrown thanks for the info. it's really interesting. I removed the container and run the both container again. then tested the settings below

LDAP_SERVER=ldap://server.domain.com:389 LDAP_START_TLS=true LDAP_TLS_INSECURE=false

it worked just fine...

I used tail -f for the laravel.log

the error i got today [2023-04-18 01:33:53] production.ERROR: Failed to save user avatar image [2023-04-18 01:34:39] production.ERROR: Failed to save user avatar image [2023-04-18 01:42:18] production.ERROR: Failed to save user avatar image

Securing LDAP over SSL Safely [Windows Server 2019] https://www.youtube.com/watch?v=8rlk2xDkgLw

I followed by the above youtube video to set up the LDAP over SSL on my DC. just for reference . Hope it helps.

jasonyunliang avatar Apr 18 '23 01:04 jasonyunliang

Now it is not working anymore, even with LDAP_TLS_INSECURE=true, did something changed ?

eoli3n avatar Apr 03 '24 09:04 eoli3n

@eoli3n Not that I'm aware of. Any changes made to the wider system recently? What is the current error logged or seen?

ssddanbrown avatar Apr 03 '24 13:04 ssddanbrown

I just retested to give you logs : it now works and we had a problem on our AD. Thanks for your answer !

eoli3n avatar Apr 03 '24 14:04 eoli3n