Mailtrain-org / mailtrain

Self hosted newsletter app
GNU General Public License v3.0
5.51k stars 693 forks source link

V2 LDAP not working #862

Closed maxemann96 closed 6 months ago

maxemann96 commented 4 years ago

Hello, I setup the server with ldap enabled, but the following messages are printed to log:

info LDAP Module "passport-ldapjs" not installed. It will not be used for LDAP auth.
info LDAP Module "passport-ldapauth" not installed. It will not be used for LDAP auth.

As indicated, mailtrain never tries to connect to my ldap server. Im using the latest docker image with the following ldap config (excerpt from mounted /app/server/config/production.yaml):

ldap:
  enabled: true
  host: openldap
  port: 389
  secure: true
  baseDN: {{ BASE_DN }}
  filter: (&(&(objectclass=inetOrgPerson)(memberof=cn=mailtrain,ou=apps,{{ BASE_DN }}))(|(cn={{username}})(|(mailPrimaryAddress={{username}})(mail={{username}}))(|(cn={{username}}))))
  uidTag: entryUUID
  nameTag: displayName
  bindUser: cn=mailtrain,ou=apps,{{ BASE_DN }}
  bindPassword: {{ PASSWORD }}

With basedn and password substituted with the correct values. Am I missing something?

maxemann96 commented 4 years ago

Further inspection revealed that passport-ldapjs is missing in /server/package.json. After adding the dependency, the server starts with confirming that the module was found. My next problem is that im getting a stack trace if I try to login (on commit f323033da755410c05de2aca5055d148414709ab):

verb HTTP TypeError: Cannot read property 'on' of undefined
verb HTTP     at setupSocket (/app/server/node_modules/ldapjs/lib/client/client.js:111:15)
verb HTTP     at Client._connect (/app/server/node_modules/ldapjs/lib/client/client.js:742:3)
verb HTTP     at new Client (/app/server/node_modules/ldapjs/lib/client/client.js:247:22)
verb HTTP     at Object.createClient (/app/server/node_modules/ldapjs/lib/client/index.js:60:12)
verb HTTP     at Strategy.authenticate (/app/server/node_modules/passport-ldapjs/lib/strategy.js:67:23)
verb HTTP     at attempt (/app/server/node_modules/passport/lib/middleware/authenticate.js:366:16)
verb HTTP     at authenticate (/app/server/node_modules/passport/lib/middleware/authenticate.js:367:7)
verb HTTP     at module.exports.restLogin (/app/server/lib/passport.js:176:7)
verb HTTP     at Layer.handle [as handle_request] (/app/server/node_modules/express/lib/router/layer.js:95:5)
verb HTTP     at next (/app/server/node_modules/express/lib/router/route.js:137:13)
verb HTTP     at csrf (/app/server/node_modules/csurf/index.js:117:5)
verb HTTP     at Layer.handle [as handle_request] (/app/server/node_modules/express/lib/router/layer.js:95:5)
verb HTTP     at next (/app/server/node_modules/express/lib/router/route.js:137:13)
verb HTTP     at Route.dispatch (/app/server/node_modules/express/lib/router/route.js:112:3)
verb HTTP     at Layer.handle [as handle_request] (/app/server/node_modules/express/lib/router/layer.js:95:5)
verb HTTP     at /app/server/node_modules/express/lib/router/index.js:281:22
verb HTTP     at Function.process_params (/app/server/node_modules/express/lib/router/index.js:335:12)
verb HTTP     at next (/app/server/node_modules/express/lib/router/index.js:275:10)
verb HTTP     at Function.handle (/app/server/node_modules/express/lib/router/index.js:174:3)
verb HTTP     at router (/app/server/node_modules/express/lib/router/index.js:47:12)
verb HTTP     at Layer.handle [as handle_request] (/app/server/node_modules/express/lib/router/layer.js:95:5)
verb HTTP     at trim_prefix (/app/server/node_modules/express/lib/router/index.js:317:13)
verb HTTP  { TypeError: Cannot read property 'on' of undefined
verb HTTP     at setupSocket (/app/server/node_modules/ldapjs/lib/client/client.js:111:15)
verb HTTP     at Client._connect (/app/server/node_modules/ldapjs/lib/client/client.js:742:3)
verb HTTP     at new Client (/app/server/node_modules/ldapjs/lib/client/client.js:247:22)
verb HTTP     at Object.createClient (/app/server/node_modules/ldapjs/lib/client/index.js:60:12)
verb HTTP     at Strategy.authenticate (/app/server/node_modules/passport-ldapjs/lib/strategy.js:67:23)
verb HTTP     at attempt (/app/server/node_modules/passport/lib/middleware/authenticate.js:366:16)
verb HTTP     at authenticate (/app/server/node_modules/passport/lib/middleware/authenticate.js:367:7)
verb HTTP     at module.exports.restLogin (/app/server/lib/passport.js:176:7)
verb HTTP     at Layer.handle [as handle_request] (/app/server/node_modules/express/lib/router/layer.js:95:5)
verb HTTP     at next (/app/server/node_modules/express/lib/router/route.js:137:13)
verb HTTP     at csrf (/app/server/node_modules/csurf/index.js:117:5)
verb HTTP     at Layer.handle [as handle_request] (/app/server/node_modules/express/lib/router/layer.js:95:5)
verb HTTP     at next (/app/server/node_modules/express/lib/router/route.js:137:13)
verb HTTP     at Route.dispatch (/app/server/node_modules/express/lib/router/route.js:112:3)
verb HTTP     at Layer.handle [as handle_request] (/app/server/node_modules/express/lib/router/layer.js:95:5)
verb HTTP     at /app/server/node_modules/express/lib/router/index.js:281:22
verb HTTP     at Function.process_params (/app/server/node_modules/express/lib/router/index.js:335:12)
verb HTTP     at next (/app/server/node_modules/express/lib/router/index.js:275:10)
verb HTTP     at Function.handle (/app/server/node_modules/express/lib/router/index.js:174:3)
verb HTTP     at router (/app/server/node_modules/express/lib/router/index.js:47:12)
verb HTTP     at Layer.handle [as handle_request] (/app/server/node_modules/express/lib/router/layer.js:95:5)
verb HTTP     at trim_prefix (/app/server/node_modules/express/lib/router/index.js:317:13)
verb HTTP   stack:
verb HTTP    'TypeError: Cannot read property \'on\' of undefined\n    at setupSocket (/app/server/node_modules/ldapjs/lib/client/client.js:111:15)\n    at Client._connect (/app/server/node_modules/ldapjs/lib/client/client.js:742:3)\n    at new Client (/app/server/node_modules/ldapjs/lib/client/client.js:247:22)\n    at Object.createClient (/app/server/node_modules/ldapjs/lib/client/index.js:60:12)\n    at Strategy.authenticate (/app/server/node_modules/passport-ldapjs/lib/strategy.js:67:23)\n    at attempt (/app/server/node_modules/passport/lib/middleware/authenticate.js:366:16)\n    at authenticate (/app/server/node_modules/passport/lib/middleware/authenticate.js:367:7)\n    at module.exports.restLogin (/app/server/lib/passport.js:176:7)\n    at Layer.handle [as handle_request] (/app/server/node_modules/express/lib/router/layer.js:95:5)\n    at next (/app/server/node_modules/express/lib/router/route.js:137:13)\n    at csrf (/app/server/node_modules/csurf/index.js:117:5)\n    at Layer.handle [as handle_request] (/app/server/node_modules/express/lib/router/layer.js:95:5)\n    at next (/app/server/node_modules/express/lib/router/route.js:137:13)\n    at Route.dispatch (/app/server/node_modules/express/lib/router/route.js:112:3)\n    at Layer.handle [as handle_request] (/app/server/node_modules/express/lib/router/layer.js:95:5)\n    at /app/server/node_modules/express/lib/router/index.js:281:22\n    at Function.process_params (/app/server/node_modules/express/lib/router/index.js:335:12)\n    at next (/app/server/node_modules/express/lib/router/index.js:275:10)\n    at Function.handle (/app/server/node_modules/express/lib/router/index.js:174:3)\n    at router (/app/server/node_modules/express/lib/router/index.js:47:12)\n    at Layer.handle [as handle_request] (/app/server/node_modules/express/lib/router/layer.js:95:5)\n    at trim_prefix (/app/server/node_modules/express/lib/router/index.js:317:13)' }
info HTTP POST /rest/login 500 34.381 ms - 63

The login answer was (http://localhost:3000/rest/login): {"message":"Cannot read property 'on' of undefined","error":{}}

stettberger commented 4 years ago

I can confirm this problem. Furthermore, on the OpenLDAP Log (with loglevel 260), I see:

openldap             | 5e945fb9 conn=1046 fd=16 ACCEPT from IP=172.20.0.1:38120 (IP=0.0.0.0:636)
openldap             | 5e945fb9 connection_get(16)
openldap             | 5e945fb9 connection_get(16)
openldap             | 5e945fb9 conn=1046 fd=16 TLS established tls_ssf=256 ssf=256

From this log, we see that the request died before the LDAP Bind was done (otherwise, there would be an indication with OpenLDAP log level 260).

maxemann96 commented 4 years ago

With passport-ldapauth instead of passport-ldapjs, the following changes:

  1. The error message changes to Cannot set property 'expires' of undefined
  2. In OpenLdap log, the filter query was successful and one user (of objectClass inetOrgPerson) was retuned
jdukewich commented 4 years ago

We had the same issues as the original comment and we think we have been able to work out LDAP successfully. Depending on which ldap library you use, we think we have solutions.

For passport-ldapauth (which we found to work more easily), you must install the dependency (whether you add that to package.json or just install in the container is up to you). However, the README never discusses an environment variable LDAP_METHOD which defaults to ldapjs. So, mailtrain will still end up using local auth in this case. So set LDAP_METHOD=ldapauth as well.

For passport-ldapjs it has an outdated dependency causing everything to break. If you want to use this module, you will have to make passport-ldapjs use "ldapjs": "^1.0.2" instead of "ldapjs": "^0.7.1".

Beware, in server/config/default.yaml the default role is set as newUserRole: master so any users who log in through LDAP will be placed as Global Masters for some reason.

Another note of caution, if you want mailtrain to actually bind to the ldap server using the correct login username and password, you will have to override the default environment variables values for LDAP_BIND_USERand LDAP_BIND_PASS. We set them to null so that the actual username and password are pulled from the request.

Also, here are the environment variables I used in my .env file (confidentiality stripped):

URL_BASE_TRUSTED=https://mail.example.com
URL_BASE_SANDBOX=https://mail-sbox.example.com
URL_BASE_PUBLIC=https://lists.example.com

WWW_PROXY=true

WITH_LDAP=true
LDAP_HOST=ldap.example.com
LDAP_PORT=636
LDAP_SECURE=true
LDAP_BASEDN=dc=example,dc=com
LDAP_UIDTAG=uid
LDAP_BIND_USER=null
LDAP_BIND_PASS=null
LDAP_METHOD=ldapauth
LDAP_FILTER=(uid={{username}})
insaaniManav commented 4 years ago

Hello, I setup the server with ldap enabled, but the following messages are printed to log:

info LDAP Module "passport-ldapjs" not installed. It will not be used for LDAP auth.
info LDAP Module "passport-ldapauth" not installed. It will not be used for LDAP auth.

As indicated, mailtrain never tries to connect to my ldap server. Im using the latest docker image with the following ldap config (excerpt from mounted /app/server/config/production.yaml):

ldap:
  enabled: true
  host: openldap
  port: 389
  secure: true
  baseDN: {{ BASE_DN }}
  filter: (&(&(objectclass=inetOrgPerson)(memberof=cn=mailtrain,ou=apps,{{ BASE_DN }}))(|(cn={{username}})(|(mailPrimaryAddress={{username}})(mail={{username}}))(|(cn={{username}}))))
  uidTag: entryUUID
  nameTag: displayName
  bindUser: cn=mailtrain,ou=apps,{{ BASE_DN }}
  bindPassword: {{ PASSWORD }}

With basedn and password substituted with the correct values. Am I missing something?

Hi may I know how do I get logs for the same ?

jdukewich commented 4 years ago

@insaaniManav See my previous answer, a lot of the content in there will help your issue. If you are using the latest docker image, its package.json will not have either of the ldap packages required. So you will either have to add one of them to the package.json file or install them yourself

bures commented 4 years ago

@jdukewich Thanks for the how-to. If you have any extensions/modifications to the docket image you think are generally applicable, please make a PR.

insaaniManav commented 4 years ago

Hi but I still want to know about how I can get the logs for the same Thanks for replying so fast :D

insaaniManav commented 4 years ago

Since my ldap is not working and I still want to know what exactly is wrong so that I can diagnose it And package.json has ldap-passport , should I add ldap to it as well ?

jdukewich commented 4 years ago

I would try to use "passport-ldapauth": "^2.1.4" in your package.json. I've found that this npm package works the easiest, it's not in the package.json by default. If stuff still doesn't work after this, it can be tricky to see exactly what is going wrong because the only logging will come from whatever mailtrain is configured to log. But for now, the message that is printed is exactly why it isn't trying to connect (i.e. you don't have the intended libraries installed).

insaaniManav commented 4 years ago

We had the same issues as the original comment and we think we have been able to work out LDAP successfully. Depending on which ldap library you use, we think we have solutions.

For passport-ldapauth (which we found to work more easily), you must install the dependency (whether you add that to package.json or just install in the container is up to you). However, the README never discusses an environment variable LDAP_METHOD which defaults to ldapjs. So, mailtrain will still end up using local auth in this case. So set LDAP_METHOD=ldapauth as well.

For passport-ldapjs it has an outdated dependency causing everything to break. If you want to use this module, you will have to make passport-ldapjs use "ldapjs": "^1.0.2" instead of "ldapjs": "^0.7.1".

Beware, in server/config/default.yaml the default role is set as newUserRole: master so any users who log in through LDAP will be placed as Global Masters for some reason.

Another note of caution, if you want mailtrain to actually bind to the ldap server using the correct login username and password, you will have to override the default environment variables values for LDAP_BIND_USERand LDAP_BIND_PASS. We set them to null so that the actual username and password are pulled from the request.

Also, here are the environment variables I used in my .env file (confidentiality stripped):

URL_BASE_TRUSTED=https://mail.example.com
URL_BASE_SANDBOX=https://mail-sbox.example.com
URL_BASE_PUBLIC=https://lists.example.com

WWW_PROXY=true

WITH_LDAP=true
LDAP_HOST=ldap.example.com
LDAP_PORT=636
LDAP_SECURE=true
LDAP_BASEDN=dc=example,dc=com
LDAP_UIDTAG=uid
LDAP_BIND_USER=null
LDAP_BIND_PASS=null
LDAP_METHOD=ldapauth
LDAP_FILTER=(uid={{username}})

Also the env variables you try to talk about here ? where do I configure them ?

jdukewich commented 4 years ago

You are running via the Docker image, using docker-compose? If so, docker-compose supports environment variable via a file. See the Docker documentation for how to set that up (https://docs.docker.com/compose/environment-variables/). Basically, you just have to make a file with your environment variables and add that file to the compose file.

insaaniManav commented 4 years ago

Oh ok thanks a ton for all this advice and yes I am using docker compose

insaaniManav commented 4 years ago

Tried everything but docker-compose logs still tell me authentication failure when I try and login via ldap

jdukewich commented 4 years ago

What are your values for your environment variables?

If you are using the values you mentioned above, I would double check the "host" because your production.yaml had host: openldap but that's not what it's looking for. It's looking for the DNS name of your ldap server. Something like ldap.example.com.

insaaniManav commented 4 years ago

I have changed to the host to the respective value in the changes.toml file . I cant find any file called production.yaml

talheim-it commented 6 months ago

We are going to start with the development and testing of mailtrain v3 in the next weeks.

You are welcome to help us with the testing as soon as the first release candidate is available.