einfallstoll / express-ntlm

An express middleware to have basic NTLM-authentication in node.js.
BSD 2-Clause "Simplified" License
89 stars 26 forks source link

NTLM on LDAP works perfectly but LDAPS, seems to not work #91

Open antonio-castellon opened 2 years ago

antonio-castellon commented 2 years ago

Hi Everyone,

I just struggling with the example provided in the web, the LDAP 389 is working pretty well, now we must move to LDAPS and suddenly I cannot use the configuration for LDAPS 636, it returns me a forbidden always. I used another LDAP browser app against the same address (ldaps) without any problems with the same user, but I cannot do the same using the example. Any idea about what I could miss?.

Many thanks in advance, Best regards Antonio

einfallstoll commented 2 years ago

Do you have any additional information? Like code you used? Or debugging information?

antonio-castellon commented 2 years ago

As I said using the example in the website (last one using ldaps) is not saying anything else than "forbidden".

on the code side:

app.use(ntlm({ debug: function() { var args = Array.prototype.slice.apply(arguments); console.log.apply(null, args); }, domain: 'MY_DOMAIN', domaincontroller: 'ldaps://ldap.mydomain.internal', tlsOptions: { rejectUnauthorized: false, } }));

throws on the console:

[express-ntlm] No Authorization header present [express-ntlm] Initiating connection to Active Directory server ldap.mydomain.internal (domain MY_DOMAIN) using base DN "null". [express-ntlm] User MY_DOMAIN/acastellon authentication for URI http://localhost:8800/

einfallstoll commented 2 years ago

Interesting, I can't really tell if there's a connection or not. It looks like the domain controller returns no result but no error either.

Maybe it's a configuration issue, as others successfully implemented this feature and it doesn't do much except for adding a TLS layer of encryption to the connection.

antonio-castellon commented 2 years ago

I tried removing the rejectUnauthorized and including the CA certificate (validated and clearly the correct one), and now I have more error messages that maybe can clarify us what is the problem behind.

> [express-ntlm] Error: unable to get issuer certificate
>     at TLSSocket.onConnectSecure (_tls_wrap.js:1514:34)
>     at TLSSocket.emit (events.js:375:28)
>     at TLSSocket._finishInit (_tls_wrap.js:936:8)
>     at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:708:12) {
>   code: 'UNABLE_TO_GET_ISSUER_CERT'
> }
> [express-ntlm] Error: None of the Domain Controllers are available.
>     at C:\DEV\@acastellon\module-rest\node_modules\express-ntlm\lib\express-ntlm.js:132:33
>     at wrapper (C:\DEV\@acastellon\module-rest\node_modules\async\dist\async.js:271:20)
>     at replenish (C:\DEV\@acastellon\module-rest\node_modules\async\dist\async.js:441:29)
>     at iterateeCallback (C:\DEV\@acastellon\module-rest\node_modules\async\dist\async.js:430:21)
>     at C:\DEV\@acastellon\module-rest\node_modules\async\dist\async.js:327:20
>     at C:\DEV\@acastellon\module-rest\node_modules\express-ntlm\lib\express-ntlm.js:121:28
>     at TLSSocket.<anonymous> (C:\DEV\@acastellon\module-rest\node_modules\express-ntlm\lib\NTLM_Proxy.js:61:13)
>     at TLSSocket.emit (events.js:375:28)
>     at emitErrorNT (internal/streams/destroy.js:106:8)
>     at emitErrorCloseNT (internal/streams/destroy.js:74:3)
> [express-ntlm] No Authorization header present
> [express-ntlm] Initiating connection to Active Directory server ldap.mydomain.internal:636 (domain MY_DOMAIN) using base DN "null".
> [express-ntlm] Error: unable to get issuer certificate
>     at TLSSocket.onConnectSecure (_tls_wrap.js:1514:34)
>     at TLSSocket.emit (events.js:375:28)
>     at TLSSocket._finishInit (_tls_wrap.js:936:8)
>     at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:708:12) {
>   code: 'UNABLE_TO_GET_ISSUER_CERT'
> }
> [express-ntlm] Error: None of the Domain Controllers are available.
>     at C:\DEV\@acastellon\module-rest\node_modules\express-ntlm\lib\express-ntlm.js:132:33
>     at wrapper (C:\DEV\@acastellon\module-rest\node_modules\async\dist\async.js:271:20)
>     at replenish (C:\DEV\@acastellon\module-rest\node_modules\async\dist\async.js:441:29)
>     at iterateeCallback (C:\DEV\@acastellon\module-rest\node_modules\async\dist\async.js:430:21)
>     at C:\DEV\@acastellon\module-rest\node_modules\async\dist\async.js:327:20
>     at C:\DEV\@acastellon\module-rest\node_modules\express-ntlm\lib\express-ntlm.js:121:28
>     at TLSSocket.<anonymous> (C:\DEV\@acastellon\module-rest\node_modules\express-ntlm\lib\NTLM_Proxy.js:61:13)
>     at TLSSocket.emit (events.js:375:28)
>     at emitErrorNT (internal/streams/destroy.js:106:8)
>     at emitErrorCloseNT (internal/streams/destroy.js:74:3)

Any idea? Many thanks in advance.

Note: Using ActiveDirectory library works perfectly to request from node to LDAPS

antonio-castellon commented 2 years ago

Ok, I dont know what library are you using to connect to ldap internally, but I used ActiveDirectory from npm with the same configuration (ca.pem included) and it works pretty well. On my side I captured the forbidden event from your library using internally this other Library to get information from the username winside ldap avoiding the exception. This is getting us time to find another alternative solution. it's a Frankenstein workaround, but it's the faster way to have at least a system that works. I will appreciate any other indication (or release) in order to have a better approach to use ntlm protocol to identify the user without exceptions Best regards Antonio

einfallstoll commented 2 years ago

Internally express-ntlm uses net for unencrypted and tls for encrypted communication to the LDAP server, and that's the only difference: https://github.com/einfallstoll/express-ntlm/blob/master/lib/NTLM_Proxy.js#L19,L23

There's also no other layer between, so we're talking directly on the raw socket. So, if the module works without TLS but doesn't with TLS, there's probably another problem.

wheilson commented 2 years ago

I am also experiencing similar issues with LDAPS. For me, LDAP works fine on all browsers across all environments. For LDAPS, only Safari browser works. Neither Chrome nor Edge on Mac or Windows work.

I tried to print NTLM type 1 message for Safari and Chrome and they seem to be different.

I tried to print the NTLM type 3 bytes response message and after using ASN.1 decoder and Hex-to-String I got following:

80090346: LdapErr: DSID-0C09059A, comment: AcceptSecurityContext error, data 80090346, v3839

Not sure if this (https://support.microsoft.com/en-us/topic/2020-ldap-channel-binding-and-ldap-signing-requirements-for-windows-kb4520412-ef185fb8-00f7-167d-744c-f299a66fc00a) has to do with anything.

nukero2000 commented 10 months ago

I experienced similar issues after LDAP channel binding was enabled on AD domain controller. Any solutions was found meanwhile?