BookStackApp / BookStack

A platform to create documentation/wiki content built with PHP & Laravel
https://www.bookstackapp.com/
MIT License
15.02k stars 1.88k forks source link

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

Open eoli3n opened 1 year ago

eoli3n commented 1 year ago

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


2. Add the certificate autority system wide for Debian 11

cp ca.crt /usr/local/share/ca-certificates/ update-ca-certificates


3. 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


4. Try to authenticate : it fails
5. Change ``LDAP_TLS_INSECURE`` to ``true``
6. 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 commented 1 year ago

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 commented 1 year ago

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

eoli3n commented 1 year ago

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

ssddanbrown commented 1 year ago

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).

eoli3n commented 1 year ago

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.

ssddanbrown commented 1 year ago

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

eoli3n commented 1 year ago

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 ?

ssddanbrown commented 1 year ago

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.

eoli3n commented 1 year ago

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

jasonyunliang commented 1 year ago

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

drie-cdts commented 1 year ago

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.

jasonyunliang commented 1 year ago

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 commented 1 year ago

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.

ssddanbrown commented 1 year ago

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

jasonyunliang commented 1 year ago

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

eoli3n commented 6 months ago

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

ssddanbrown commented 6 months ago

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

eoli3n commented 6 months ago

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