wekan / ldap

LDAP support for Wekan code has been moved to https://github.com/wekan/wekan/tree/master/packages/wekan-ldap , issues to https://github.com/wekan/wekan/issues , and if PRs are needed please add them instead to https://github.com/wekan/wekan/pulls
https://github.com/wekan/wekan/tree/master/packages/wekan-ldap
MIT License
12 stars 10 forks source link

Object Error after LDAP login #51

Open bkraul opened 4 years ago

bkraul commented 4 years ago

Issue

Server Setup Information:

Problem description: LDAP login takes place, but there is an error, and the login screen continues to appear. The log shows that the LDAP authentication happened successfully but then there is an error on the login action.

There had been no issues with the LDAP part of it. It is only after the last few updates. Any help would be appreciated, as I don't want to have to rebuild without first finding out what the problem is.

badlogin

Steps to reproduce

Docker stdout log (asterisks for privacy)

[INFO] LDAP connected 
[INFO] Binding UserDN "cn=serviceaccount,ou=Administrators,dc=mydomain,dc=com"
[INFO] Searching user "bkraul"
[DEBUG] searchOptions {
  "filter": "(&(sAMAccountName=bkraul))",
  "scope": "sub",
  "sizeLimit": 0
}
[DEBUG] BaseDN "ou=*****,ou=****,dc=mydomain,dc=com"
[INFO] Search result count 1
[INFO] Authenticating "CN=Belman Kraul,OU=IT,OU=****,OU=****,DC=mydomain,DC=com"
[INFO] Authenticated "CN=Belman Kraul,OU=IT,OU=****,OU=EPGU****sers,DC=mydomain,DC=com"
[DEBUG] Identifying user with: sAMAccountName 
[INFO] Querying user 
[DEBUG] userQuery {
  "services.ldap.id": "*******"
}
[INFO] Logging user 
[DEBUG] Updating admin status 
Exception while invoking method 'login' [object Object]

The interesting thing is that I can't copy any more lines after that line, as there are some special characters in the object...

I have tried to figure out how to get more information from that exception, but I am at a loss.

xet7 commented 4 years ago

Login for LDAP etc uses email address as username.

bkraul commented 4 years ago

Unfortunately that seems not to be the case. This is the input of the log with using email address attached to that account:

[INFO] LDAP connected 
[INFO] Binding UserDN "cn=serviceaccount,ou=Administrators,dc=mydomain,dc=com"
[INFO] Searching user "bkraul@epgins.com"
[DEBUG] searchOptions {
  "filter": "(&(sAMAccountName=bkraul@mydomain.com))",
  "scope": "sub",
  "sizeLimit": 0
}
[DEBUG] BaseDN "ou=****,ou=****,dc=mydomain,dc=com"
[INFO] Search result count 
[INFO] Search returned 
[ERROR] Error: User not Found 

Again, this had been working for months. It's not like it has never worked...And as you can see from the log in the original post, the authentication itself is working. It is once it gets back to wekan that it is erroring out.

Really, all I need is a way to see the contents of that [object Object] item. Is there a more detailed log inside the container that I can go check?

xet7 commented 4 years ago

For Docker, this setting in docker-compose.yml:

- DEBUG=true

And after you try login:

docker logs wekan-app

Did you delete old docker container when you upgraded?

docker-compose stop
docker rm wekan-app
docker-compose up -d

Are you using newest docker-compose.yml from https://github.com/wekan/wekan ?

xet7 commented 4 years ago

Is there errors at mongodb?

docker logs wekan-db

Did you do backup and upgrade with --noIndexRestore ? https://github.com/wekan/wekan/issues/2533#issuecomment-517999731

bkraul commented 4 years ago

Activated DEBUG=true. Output on login attempt is:

wekan-db   | 2019-08-14T17:04:22.465+0000 I NETWORK  [listener] connection accepted from 172.24.0.3:40608 wekan/wekan#2 (2 connections now open)
wekan-db   | 2019-08-14T17:04:22.995+0000 I NETWORK  [listener] connection accepted from 172.24.0.3:40610 wekan/wekan#3 (3 connections now open)
wekan-db   | 2019-08-14T17:04:23.708+0000 I NETWORK  [listener] connection accepted from 172.24.0.3:40612 wekan/wekan#4 (4 connections now open)
wekan-db   | 2019-08-14T17:04:23.745+0000 I NETWORK  [listener] connection accepted from 172.24.0.3:40614 wekan/wekan#5 (5 connections now open)
wekan-app  | Meteor APM: completed instrumenting the app
wekan-app  | [INFO] Init LDAP login "bkraul"
wekan-app  | [WARN] Lookup for unset variable: INTERNAL_LOG_LEVEL
wekan-app  | [WARN] Lookup for unset variable: LDAP_USER_ATTRIBUTES
wekan-app  | [INFO] Init setup
wekan-app  | [INFO] Connecting "ldap://dc.mydomain.com:389"
wekan-app  | [DEBUG] connectionOptions{ url: 'ldap://dc.mydomain.com:389',
wekan-app  |   timeout: 10000,
wekan-app  |   connectTimeout: 10000,
wekan-app  |   idleTimeout: 10000,
wekan-app  |   reconnect: true,
wekan-app  |   log:
wekan-app  |    Logger {
wekan-app  |      domain: null,
wekan-app  |      _events: {},
wekan-app  |      _eventsCount: 0,
wekan-app  |      _maxListeners: undefined,
wekan-app  |      _level: 30,
wekan-app  |      streams: [ [Object] ],
wekan-app  |      serializers: null,
wekan-app  |      src: false,
wekan-app  |      fields:
wekan-app  |       { name: 'ldapjs',
wekan-app  |         component: 'client',
wekan-app  |         hostname: '8d1c6e9fd4e9',
wekan-app  |         pid: 1 } } }
wekan-app  | [INFO] LDAP connected
wekan-app  | [INFO] Binding UserDN "cn=serviceaccount,ou=Administrators,dc=mydomain,dc=com"
wekan-app  | [INFO] Searching user "bkraul"
wekan-app  | [DEBUG] searchOptions {
wekan-app  |   "filter": "(&(sAMAccountName=bkraul))",
wekan-app  |   "scope": "sub",
wekan-app  |   "sizeLimit": 0
wekan-app  | }
wekan-app  | [DEBUG] BaseDN "ou=****,ou=****,dc=mydomain,dc=com"
wekan-app  | [INFO] Search result count 1
wekan-app  | [INFO] Authenticating "CN=Belman Kraul,OU=IT,OU=****,OU=****,DC=mydomain,DC=com"
wekan-app  | [INFO] Authenticated "CN=Belman Kraul,OU=IT,OU=***,OU=****,DC=mydomain,DC=com"
wekan-app  | [DEBUG] Identifying user with: sAMAccountName
wekan-app  | [INFO] Querying user
wekan-app  | [DEBUG] userQuery {
wekan-app  |   "services.ldap.id": "626b7261756c"
wekan-app  | }
wekan-app  | [INFO] Logging user
wekan-app  | [DEBUG] Updating admin status
wekan-app  | Exception while invoking method 'login' [object Object]
wekan-app  | [INFO] Idle
wekan-app  | [INFO] Disconecting
wekan-app  | [INFO] Closed

I am using docker-compose, so I made sure to completely remove containers and redo. I also removed the image and re-pulled it just to be safe.

Mongo is not reporting any error whatsoever, only successfull connections as per this log:

2019-08-14T17:04:20.327+0000 I FTDC     [initandlisten] Initializing full-time diagnostic data capture with directory '/data/db/diagnostic.data'
2019-08-14T17:04:20.329+0000 I NETWORK  [initandlisten] waiting for connections on port 27017
2019-08-14T17:04:21.162+0000 I NETWORK  [listener] connection accepted from 172.24.0.3:40606 wekan/wekan#1 (1 connection now open)
2019-08-14T17:04:21.171+0000 I NETWORK  [conn1] received client metadata from 172.24.0.3:40606 conn1: { driver: { name: "nodejs", version: "3.1.13" }, os: { type: "Linux", name: "linux", architecture: "x64", version: "4.15.0-58-generic" }, platform: "Node.js v8.16.0, LE, mongodb-core: 3.1.11" }
2019-08-14T17:04:22.465+0000 I NETWORK  [listener] connection accepted from 172.24.0.3:40608 wekan/wekan#2 (2 connections now open)
2019-08-14T17:04:22.995+0000 I NETWORK  [listener] connection accepted from 172.24.0.3:40610 wekan/wekan#3 (3 connections now open)
2019-08-14T17:04:23.708+0000 I NETWORK  [listener] connection accepted from 172.24.0.3:40612 wekan/wekan#4 (4 connections now open)
2019-08-14T17:04:23.745+0000 I NETWORK  [listener] connection accepted from 172.24.0.3:40614 wekan/wekan#5 (5 connections now open)

I have not verified that I am using the newest docker-compose.yml, but I am going to do that next and check for major changes.

bkraul commented 4 years ago

Compared the compose files, there is not a whole lot of changes, and I had already been using Mongo 4.0 all along from the moment I first deployed the stack.

Left: github, Right: My current image

xet7 commented 4 years ago

@Akuket

Do you have time to look at this?

bkraul commented 4 years ago

I'm assuming there is not an easy way that I can bash into the wekan-app container, issue a command, and see the result of [object Object]?

xet7 commented 4 years ago

If that object is array etc, it should maybe be changed to string or something.

It would be nice that some Wekan LDAP user/contributor could help looking at this. I have not done Wekan LDAP code.

bkraul commented 4 years ago

I am really not sure this is tied to LDAP though. I am in the process of doing a backup/restore for good measure.

UPDATE: backup/restore done per instructions. Made no difference.

bkraul commented 4 years ago

If that object is array etc, it should maybe be changed to string or something.

It would be nice that some Wekan LDAP user/contributor could help looking at this. I have not done Wekan LDAP code.

@xet7, how do I go about changing the array to string? If there was any way to force more detailed debug info, that would help.

bkraul commented 4 years ago

Also, I tried this with a brand new install (to discount the possibility of a corrupted db). The result was the same, still getting the same error.

xet7 commented 4 years ago

In general, array has many items. So in code with Javascript you read each array item an in loop do same thing to all variables.

At https://github.com/wekan/wekan repo is rebuild-wekan.sh, run it with option 1 to install dependencies and then option 2 to build Wekan. Then add your docker settings to start-wekan.sh .

xet7 commented 4 years ago

Array means some of your LDAP fields has multiple values, like many email addresses etc. I think the reason why others don't have this error is that they only have one value on that field.

You can also try to login with some other user.

It's also possible that some of your LDAP settings are not correct. What are your LDAP settings? Please anonymize values before adding those as comment to this issue.

bkraul commented 4 years ago

I will post those later today. However, here is the kicker, they have been working for months until recent wekan updates. Nothing has changed in the LDAP config.

bkraul commented 4 years ago

Here are my LDAP settings:

# The default authentication method used if a user does not exist to create and authenticate. Can be set as ldap.
- DEFAULT_AUTHENTICATION_METHOD=ldap
#
# Enable or not the connection by the LDAP
- LDAP_ENABLE=true
#
# The port of the LDAP server
- LDAP_PORT=389
#
# The host server for the LDAP server
- LDAP_HOST=dc.mydomain.com
#
# The base DN for the LDAP Tree
- LDAP_BASEDN=ou=myou2,ou=myou1,dc=mydomain,dc=com
#
# Fallback on the default authentication method
- LDAP_LOGIN_FALLBACK=false
#
# Reconnect to the server if the connection is lost
- LDAP_RECONNECT=true
#
# Overall timeout, in milliseconds
- LDAP_TIMEOUT=10000
#
# Specifies the timeout for idle LDAP connections in milliseconds
- LDAP_IDLE_TIMEOUT=10000
#
# Connection timeout, in milliseconds
- LDAP_CONNECT_TIMEOUT=10000
#
# If the LDAP needs a user account to search
- LDAP_AUTHENTIFICATION=true
#
# The search user DN
- LDAP_AUTHENTIFICATION_USERDN=cn=serviceaccount,ou=Administrators,dc=mydomain,dc=com
#
# The password for the search user
- LDAP_AUTHENTIFICATION_PASSWORD=MySuperSecretPassword
#
# Enable logs for the module
- LDAP_LOG_ENABLED=true
#
# If the sync of the users should be done in the background
- LDAP_BACKGROUND_SYNC=false
#
# At which interval does the background task sync in milliseconds
- LDAP_BACKGROUND_SYNC_INTERVAL=100
#
- LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED=false
#
- LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS=false
#
# If using LDAPS: LDAP_ENCRYPTION=ssl
- LDAP_ENCRYPTION=false
#
# The certification for the LDAPS server. Certificate needs to be included in this docker-compose.yml file.
- LDAP_CA_CERT=-----BEGIN CERTIFICATE-----MIIE+G2FIdAgIC...-----END CERTIFICATE-----
#
# Reject Unauthorized Certificate
- LDAP_REJECT_UNAUTHORIZED=false
#
# Optional extra LDAP filters. Don't forget the outmost enclosing parentheses if needed
- LDAP_USER_SEARCH_FILTER=
#
# base (search only in the provided DN), one (search only in the provided DN and one level deep), or sub (search the whole subtree)
- LDAP_USER_SEARCH_SCOPE=sub
#
# Which field is used to find the user, like uid / sAMAccountName
- LDAP_USER_SEARCH_FIELD=sAMAccountName
#
# Used for pagination (0=unlimited)
- LDAP_SEARCH_PAGE_SIZE=0
#
# The limit number of entries (0=unlimited)
- LDAP_SEARCH_SIZE_LIMIT=0
#
# Enable group filtering
- LDAP_GROUP_FILTER_ENABLE=false
- P_FILTER_GROUP_ID_ATTRIBUTE=
#
- LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE=
#
- LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT=
#
- LDAP_GROUP_FILTER_GROUP_NAME=
#
#LDAP_UNIQUE_IDENTIFIER_FIELD : This field is sometimes class GUID (Globally Unique Identifier). Example: guid
- LDAP_UNIQUE_IDENTIFIER_FIELD=
#
# LDAP_UTF8_NAMES_SLUGIFY : Convert the username to utf8
- LDAP_UTF8_NAMES_SLUGIFY=true
#
# LDAP_USERNAME_FIELD : Which field contains the ldap username. username / sAMAccountName
- LDAP_USERNAME_FIELD=sAMAccountName
#
# LDAP_FULLNAME_FIELD : Which field contains the ldap fullname. fullname / sAMAccountName
- LDAP_FULLNAME_FIELD=displayName
#
- LDAP_MERGE_EXISTING_USERS=false
#
# Allow existing account matching by e-mail address when username does not match
- LDAP_EMAIL_MATCH_ENABLE=true
#
# LDAP_EMAIL_MATCH_REQUIRE : require existing account matching by e-mail address when username does match
- LDAP_EMAIL_MATCH_REQUIRE=true
#
# LDAP_EMAIL_MATCH_VERIFIED : require existing account email address to be verified for matching
- LDAP_EMAIL_MATCH_VERIFIED=true
#
# LDAP_EMAIL_FIELD : which field contains the LDAP e-mail address
- LDAP_EMAIL_FIELD=mail
#-----------------------------------------------------------------
- LDAP_SYNC_USER_DATA=false
#
- LDAP_SYNC_USER_DATA_FIELDMAP={"cn":"name", "mail":"email"}
#
- LDAP_SYNC_GROUP_ROLES=''
#
# The default domain of the ldap it is used to create email if the field is not map correctly with the LDAP_SYNC_USER_DATA_FIELDMAP
# example :
- LDAP_DEFAULT_DOMAIN=mydomain.com
#
# Enable/Disable syncing of admin status based on ldap groups:
- LDAP_SYNC_ADMIN_STATUS=true
#
# Comma separated list of admin group names to sync.
- LDAP_SYNC_ADMIN_GROUPS=

I know I sound like a broken record, but this WORKED just fine since the very first time I implemented it, it was only after recent wekan updates that it stopped working.

xet7 commented 4 years ago

Please uncomment # those options where you do not set new value, for example this, because having empty quotes, and extra quotes in general, can cause value not set correctly:

- LDAP_SYNC_GROUP_ROLES=''
xet7 commented 4 years ago

Please uncomment this:

# At which interval does the background task sync in milliseconds
- LDAP_BACKGROUND_SYNC_INTERVAL=100
xet7 commented 4 years ago

If you want to set some LDAP group as admin, you need to define what LDAP group is admin in 2nd settings, otherwise everyone is admin. Or alternatively, uncomment both.

# Enable/Disable syncing of admin status based on ldap groups:
- LDAP_SYNC_ADMIN_STATUS=true
#
# Comma separated list of admin group names to sync.
- LDAP_SYNC_ADMIN_GROUPS=
xet7 commented 4 years ago

I would recommend that you use newest docker-compose.yml from https://github.com/wekan/wekan and add to it your current settings.

Many Wekan users also like to disable bigevents to get less email notifications: https://github.com/wekan/wekan/blob/master/docker-compose.yml#L266

xet7 commented 4 years ago

At which interval does the background task sync in milliseconds

  • LDAP_BACKGROUND_SYNC_INTERVAL=100

Just additional note about this, this is because now Wekan has LDAP user sync with synced cron, and that variable needs to be not set at all for default sync interval, and in text date format if different sync schedule is set, it can not be 100 because then Wekan does not work, see https://github.com/wekan/wekan/pull/2555

xet7 commented 4 years ago

For some other Wekan user, Wekan works with these settings:

- MONGO_URL=mongodb://wekandb:27017/wekan
- ROOT_URL=...
- MAIL_URL=...
- MAIL_FROM=...
- WITH_API=true
- BROWSER_POLICY_ENABLED=true
- LDAP_ENABLE=true
- LDAP_PORT=389
- LDAP_HOST=host
- LDAP_BASEDN=dn
- LDAP_AUTHENTIFICATION=true
- LDAP_AUTHENTIFICATION_USERDN=login
- LDAP_AUTHENTIFICATION_PASSWORD=pwd
- LDAP_LOG_ENABLED=true
- LDAP_USER_SEARCH_FIELD=samaccountname
- LDAP_USERNAME_FIELD=samaccountname
- LDAP_FULLNAME_FIELD=CN
bkraul commented 4 years ago

Performed all steps as directed, including using the updated docker-compose.yml from github. The result is the same (asterisks for privacy):

[INFO] Binding UserDN "CN=ldapserviceaccount,OU=*****,OU=*****,OU=****,DC=mydomain,DC=com"
[INFO] Searching user "bkraul"
[DEBUG] searchOptions {
  "filter": "(&(sAMAccountName=bkraul))",
  "scope": "sub",
  "sizeLimit": 0
}
[DEBUG] BaseDN "ou=*****,ou=*****,dc=
,mydomain,dc=com"
[INFO] Search result count 1
[INFO] Authenticating "CN=Belman Kraul,OU=IT,OU=******,OU=*****,DC=mydomain,DC=com"
[INFO] Authenticated "CN=Belman Kraul,OU=IT,OU=******,OU=******,DC=mydomain,DC=com"
[DEBUG] Identifying user with: sAMAccountName 
[INFO] Querying user 
[DEBUG] userQuery {
  "services.ldap.id": "626b7261756c"
}
[INFO] Logging user 
[DEBUG] Updating admin status 
Exception while invoking method 'login' [object Object]

As you can see from the log, once again, the user is being authenticated by LDAP just fine. It seems that once it gets back to wekan to apply the login method, it fails, which yields the object I can't seem to get more info on.

I am attaching a full copy of the compose file so that you can see I am using the updated one, with all subsequent suggestions applied (minus sensitive info, and environment customizations, of course).

version: '2'

# Note: Do not add single quotes '' to variables. Having spaces still works without quotes where required.
#---------------------------------------------------------------------------------------------------------
# ==== CREATING USERS AND LOGGING IN TO WEKAN ====
# https://github.com/wekan/wekan/wiki/Adding-users
#---------------------------------------------------------------------------------------------------------
# ==== FORGOT PASSWORD ====
# https://github.com/wekan/wekan/wiki/Forgot-Password
#---------------------------------------------------------------------------------------------------------
# ==== Upgrading Wekan to new version =====
# NOTE: MongoDB has changed from 3.x to 4.x, in that case you need backup/restore with --noIndexRestore
#       see https://github.com/wekan/wekan/wiki/Backup
# 1) Stop Wekan:
#      docker-compose stop
# 2) Download new version:
#      docker-compose pull wekan
# 3) If you have more networks for VPN etc as described at bottom of
#    this config, download for them too:
#      docker-compose pull wekan2
# 4) Start Wekan:
#      docker-compose start
#----------------------------------------------------------------------------------
# ==== OPTIONAL: DEDICATED DOCKER USER ====
# 1) Optionally create a dedicated user for Wekan, for example:
#      sudo useradd -d /home/wekan -m -s /bin/bash wekan
# 2) Add this user to the docker group, then logout+login or reboot:
#      sudo usermod -aG docker wekan
# 3) Then login as user wekan.
# 4) Create this file /home/wekan/docker-compose.yml with your modifications.
#----------------------------------------------------------------------------------
# ==== RUN DOCKER AS SERVICE ====
# 1a) Running Docker as service, on Systemd like Debian 9, Ubuntu 16.04, CentOS 7:
#      sudo systemctl enable docker
#      sudo systemctl start docker
# 1b) Running Docker as service, on init.d like Debian 8, Ubuntu 14.04, CentOS 6:
#      sudo update-rc.d docker defaults
#      sudo service docker start
# ----------------------------------------------------------------------------------
# ==== USAGE OF THIS docker-compose.yml ====
# 1) For seeing does Wekan work, try this and check with your webbroser:
#      docker-compose up
# 2) Stop Wekan and start Wekan in background:
#     docker-compose stop
#     docker-compose up -d
# 3) See running Docker containers:
#     docker ps
# 4) Stop Docker containers:
#     docker-compose stop
# ----------------------------------------------------------------------------------
# ===== INSIDE DOCKER CONTAINERS, AND BACKUP/RESTORE ====
# https://github.com/wekan/wekan/wiki/Backup
# If really necessary, repair MongoDB: https://github.com/wekan/wekan-mongodb/issues/6#issuecomment-424004116
# 1) Going inside containers:
#    a) Wekan app, does not contain data
#         docker exec -it wekan-app bash
#    b) MongoDB, contains all data
#         docker exec -it wekan-db bash
# 2) Copying database to outside of container:
#      docker exec -it wekan-db bash
#      cd /data
#      mongodump
#      exit
#      docker cp wekan-db:/data/dump .
# 3) Restoring database
#      # 1) Stop wekan
#             docker stop wekan-app
#      # 2) Go inside database container
#             docker exec -it wekan-db bash
#      # 3) and data directory
#             cd /data
#      # 4) Remove previos dump
#             rm -rf dump
#      # 5) Exit db container
#             exit
#      # 6) Copy dump to inside docker container
#             docker cp dump wekan-db:/data/
#      # 7) Go inside database container
#             docker exec -it wekan-db bash
#      # 8) and data directory
#             cd /data
#      # 9) Restore
#             mongorestore --drop
#      # 10) Exit db container
#             exit
#      # 11) Start wekan
#             docker start wekan-app
#-------------------------------------------------------------------------

services:

  wekandb:
    #-------------------------------------------------------------------------------------
    # ==== MONGODB AND METEOR VERSION ====
    # a) For Wekan Meteor 1.8.x version at master branch, use mongo 4.x
    image: mongo:4.0
    # b) For Wekan Meteor 1.6.x version at devel branch.
    # Only for Snap and Sandstorm while they are not upgraded yet to Meteor 1.8.x
    #image: mongo:3.2.21
    #-------------------------------------------------------------------------------------
    container_name: wekan-db
    restart: always
    command: mongod --smallfiles --oplogSize 128
    networks:
      - default
    expose:
      - 27017
    volumes:
      - /root/docker-persist/wekan/db:/data/db
      - /root/docker-persist/wekan/dump:/dump

  wekan:
    #-------------------------------------------------------------------------------------
    # ==== MONGODB AND METEOR VERSION ====
    # NOTE: Quay is currently not updated, use Docker Hub image below c)
    # a) For Wekan Meteor 1.8.x version at master branch,
    #    using https://quay.io/wekan/wekan automatic builds
    image: wekanteam/wekan
    # b) Using specific Meteor 1.6.x version tag:
    # image: quay.io/wekan/wekan:v1.95
    # c) Using Docker Hub automatic builds https://hub.docker.com/r/wekanteam/wekan
    #image: wekanteam/wekan
    # image: wekanteam/wekan:v2.99
    #-------------------------------------------------------------------------------------
    container_name: wekan-app
    restart: always
    networks:
      - default
      - reverse-proxy
    #-------------------------------------------------------------------------------------
    # ==== BUILD wekan-app DOCKER CONTAINER FROM SOURCE, if you uncomment these ====
    # ==== and use commands: docker-compose up -d --build
    #build:
    #  context: .
    #  dockerfile: Dockerfile
    #  args:
    #    - NODE_VERSION=${NODE_VERSION}
    #    - METEOR_RELEASE=${METEOR_RELEASE}
    #    - NPM_VERSION=${NPM_VERSION}
    #    - ARCHITECTURE=${ARCHITECTURE}
    #    - SRC_PATH=${SRC_PATH}
    #    - METEOR_EDGE=${METEOR_EDGE}
    #    - USE_EDGE=${USE_EDGE}
    #-------------------------------------------------------------------------------------
    #ports:
      # Docker outsideport:insideport. Do not add anything extra here.
      # For example, if you want to have wekan on port 3001,
      # use 3001:8080 . Do not add any extra address etc here, that way it does not work.
      # remove port mapping if you use nginx reverse proxy, port 8080 is already exposed to wekan-tier network
      #- 80:8080
    environment:
      # ---- begin jwilder/nginx-proxy vars ----
      - VIRTUAL_HOST=dev-wekan.mydomain.com
      - VIRTUAL_PORT=8080
      # ---- end jwilder/nginx-proxy vars ----
      - MONGO_URL=mongodb://wekandb:27017/wekan
      #---------------------------------------------------------------
      # ==== ROOT_URL SETTING ====
      # Change ROOT_URL to your real Wekan URL, for example:
      # If you have Caddy/Nginx/Apache providing SSL
      #  - https://example.com
      #  - https://boards.example.com
      # This can be problematic with avatars https://github.com/wekan/wekan/issues/1776
      #  - https://example.com/wekan
      # If without https, can be only wekan node, no need for Caddy/Nginx/Apache if you don't need them
      #  - http://example.com
      #  - http://boards.example.com
      #  - http://192.168.1.100    <=== using at local LAN
      - ROOT_URL=https://dev-wekan.mydomain.com  #   <=== using only at same laptop/desktop where Wekan is installed
      #---------------------------------------------------------------
      # ==== EMAIL SETTINGS ====
      # Email settings are required in both MAIL_URL and Admin Panel,
      #   see https://github.com/wekan/wekan/wiki/Troubleshooting-Mail
      #   For SSL in email, change smtp:// to smtps://
      # NOTE: Special characters need to be url-encoded in MAIL_URL.
      #       You can encode those characters for example at: https://www.urlencoder.org
      #- MAIL_URL=smtp://user:pass@mailserver.example.com:25/
      - MAIL_URL='smtp://exchange.mydomain.com:25/?ignoreTLS=true'
      - MAIL_FROM='Wekan Notifications <noreply.wekan@mydomain.com>'
      #---------------------------------------------------------------
      # ==== OPTIONAL: MONGO OPLOG SETTINGS =====
      # https://github.com/wekan/wekan-mongodb/issues/2#issuecomment-378343587
      # We've fixed our CPU usage problem today with an environment
      # change around Wekan. I wasn't aware during implementation
      # that if you're using more than 1 instance of Wekan
      # (or any MeteorJS based tool) you're supposed to set
      # MONGO_OPLOG_URL as an environment variable.
      # Without setting it, Meteor will perform a pull-and-diff
      # update of it's dataset. With it, Meteor will update from
      # the OPLOG. See here
      #   https://blog.meteor.com/tuning-meteor-mongo-livedata-for-scalability-13fe9deb8908
      # After setting
      # MONGO_OPLOG_URL=mongodb://<username>:<password>@<mongoDbURL>/local?authSource=admin&replicaSet=rsWekan
      # the CPU usage for all Wekan instances dropped to an average
      # of less than 10% with only occasional spikes to high usage
      # (I guess when someone is doing a lot of work)
      # - MONGO_OPLOG_URL=mongodb://<username>:<password>@<mongoDbURL>/local?authSource=admin&replicaSet=rsWekan
      #---------------------------------------------------------------
      # ==== OPTIONAL: KADIRA PERFORMANCE MONITORING FOR METEOR ====
      # https://github.com/edemaine/kadira-compose
      # https://github.com/meteor/meteor-apm-agent
      # https://blog.meteor.com/kadira-apm-is-now-open-source-490469ffc85f
      #- APM_OPTIONS_ENDPOINT=http://<kadira-ip>:11011
      #- APM_APP_ID=
      #- APM_APP_SECRET=
      #---------------------------------------------------------------
      # ==== OPTIONAL: LOGS AND STATS ====
      # https://github.com/wekan/wekan/wiki/Logs
      #
      # Daily export of Wekan changes as JSON to Logstash and ElasticSearch / Kibana (ELK)
      # https://github.com/wekan/wekan-logstash
      #
      # Statistics Python script for Wekan Dashboard
      # https://github.com/wekan/wekan-stats
      #
      # Console, file, and zulip logger on database changes https://github.com/wekan/wekan/pull/1010
      # with fix to replace console.log by winston logger https://github.com/wekan/wekan/pull/1033
      # but there could be bug https://github.com/wekan/wekan/issues/1094
      #
      # There is Feature Request: Logging date and time of all activity with summary reports,
      # and requesting reason for changing card to other column https://github.com/wekan/wekan/issues/1598
      #---------------------------------------------------------------
      # ==== WEKAN API AND EXPORT BOARD ====
      # Wekan Export Board works when WITH_API=true.
      # https://github.com/wekan/wekan/wiki/REST-API
      # https://github.com/wekan/wekan-gogs
      # If you disable Wekan API with false, Export Board does not work.
      - WITH_API=true
      #---------------------------------------------------------------
      # ==== PASSWORD BRUTE FORCE PROTECTION ====
      #https://atmospherejs.com/lucasantoniassi/accounts-lockout
      #Defaults below. Uncomment to change. wekan/server/accounts-lockout.js
      #- ACCOUNTS_LOCKOUT_KNOWN_USERS_FAILURES_BEFORE=3
      #- ACCOUNTS_LOCKOUT_KNOWN_USERS_PERIOD=60
      #- ACCOUNTS_LOCKOUT_KNOWN_USERS_FAILURE_WINDOW=15
      #- ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURES_BERORE=3
      #- ACCOUNTS_LOCKOUT_UNKNOWN_USERS_LOCKOUT_PERIOD=60
      #- ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW=15
      #---------------------------------------------------------------
      # ==== STORE ATTACHMENT ON SERVER FILESYSTEM INSTEAD OF MONGODB ====
      # https://github.com/wekan/wekan/pull/2603
      #- ATTACHMENTS_STORE_PATH = <pathname> # pathname can be relative or fullpath
      #---------------------------------------------------------------
      # ==== RICH TEXT EDITOR IN CARD COMMENTS ====
      # https://github.com/wekan/wekan/pull/2560
      - RICHER_CARD_COMMENT_EDITOR=true
      #---------------------------------------------------------------
      # ==== CARD OPENED, SEND WEBHOOK MESSAGE ====
      # https://github.com/wekan/wekan/issues/2518
      - CARD_OPENED_WEBHOOK_ENABLED=false
      #---------------------------------------------------------------
      # ==== Allow to shrink attached/pasted image ====
      # https://github.com/wekan/wekan/pull/2544
      #-MAX_IMAGE_PIXEL=1024
      #-IMAGE_COMPRESS_RATIO=80
      #---------------------------------------------------------------
      # ==== BIGEVENTS DUE ETC NOTIFICATIONS =====
      # https://github.com/wekan/wekan/pull/2541
      # Introduced a system env var BIGEVENTS_PATTERN default as "due",
      # so any activityType matches the pattern, system will send out
      # notifications to all board members no matter they are watching
      # or tracking the board or not. Owner of the wekan server can
      # disable the feature by setting this variable to "NONE" or
      # change the pattern to any valid regex. i.e. '|' delimited
      # activityType names.
      # a) Default
      #- BIGEVENTS_PATTERN=due
      # b) All
      #- BIGEVENTS_PATTERN=received|start|due|end
      # c) Disabled
      #- BIGEVENTS_PATTERN=NONE
      #---------------------------------------------------------------
      # ==== EMAIL DUE DATE NOTIFICATION =====
      # https://github.com/wekan/wekan/pull/2536
      # System timelines will be showing any user modification for
      # dueat startat endat receivedat, also notification to
      # the watchers and if any card is due, about due or past due.
      #
      # Notify due days, default 2 days before and after. 0 = due notifications disabled. Default: 2
      #- NOTIFY_DUE_DAYS_BEFORE_AND_AFTER=2
      #
      # Notify due at hour of day. Default every morning at 8am. Can be 0-23.
      # If env variable has parsing error, use default. Notification sent to watchers.
      #- NOTIFY_DUE_AT_HOUR_OF_DAY=8
      #-----------------------------------------------------------------
      # ==== EMAIL NOTIFICATION TIMEOUT, ms =====
      # Defaut: 30000 ms = 30s
      #- EMAIL_NOTIFICATION_TIMEOUT=30000
      #-----------------------------------------------------------------
      # ==== CORS =====
      # CORS: Set Access-Control-Allow-Origin header.
      #- CORS=*
      # CORS_ALLOW_HEADERS: Set Access-Control-Allow-Headers header.  "Authorization,Content-Type" is required for cross-origin use of the API.
      #- CORS_ALLOW_HEADERS=Authorization,Content-Type
      # CORS_EXPOSE_HEADERS: Set Access-Control-Expose-Headers header.  This is not needed for typical CORS situations
      #- CORS_EXPOSE_HEADERS=*
      #-----------------------------------------------------------------
      # ==== MATOMO INTEGRATION ====
      # Optional: Integration with Matomo https://matomo.org that is installed to your server
      # The address of the server where Matomo is hosted.
      #- MATOMO_ADDRESS=https://example.com/matomo
      # The value of the site ID given in Matomo server for Wekan
      #- MATOMO_SITE_ID=1
      # The option do not track which enables users to not be tracked by matomo
      #- MATOMO_DO_NOT_TRACK=true
      # The option that allows matomo to retrieve the username:
      #- MATOMO_WITH_USERNAME=true
      #-----------------------------------------------------------------
      # ==== BROWSER POLICY AND TRUSTED IFRAME URL ====
      # Enable browser policy and allow one trusted URL that can have iframe that has Wekan embedded inside.
      # Setting this to false is not recommended, it also disables all other browser policy protections
      # and allows all iframing etc. See wekan/server/policy.js
      - BROWSER_POLICY_ENABLED=true
      # When browser policy is enabled, HTML code at this Trusted URL can have iframe that embeds Wekan inside.
      #- TRUSTED_URL=https://intra.example.com
      #-----------------------------------------------------------------
      # ==== OUTGOING WEBHOOKS ====
      # What to send to Outgoing Webhook, or leave out. Example, that includes all that are default: cardId,listId,oldListId,boardId,comment,user,card,commentId .
      #- WEBHOOKS_ATTRIBUTES=cardId,listId,oldListId,boardId,comment,user,card,commentId
      #-----------------------------------------------------------------
      # ==== Debug OIDC OAuth2 etc ====
      - DEBUG=true
      #-----------------------------------------------------------------
      # ==== OAUTH2 AZURE ====
      # https://github.com/wekan/wekan/wiki/Azure
      # 1) Register the application with Azure. Make sure you capture
      #    the application ID as well as generate a secret key.
      # 2) Configure the environment variables. This differs slightly
      #     by installation type, but make sure you have the following:
      #- OAUTH2_ENABLED=true
      # OAuth2 login style: popup or redirect.
      #- OAUTH2_LOGIN_STYLE=redirect
      # Application GUID captured during app registration:
      #- OAUTH2_CLIENT_ID=xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx
      # Secret key generated during app registration:
      #- OAUTH2_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
      #- OAUTH2_SERVER_URL=https://login.microsoftonline.com/
      #- OAUTH2_AUTH_ENDPOINT=/oauth2/v2.0/authorize
      #- OAUTH2_USERINFO_ENDPOINT=https://graph.microsoft.com/oidc/userinfo
      #- OAUTH2_TOKEN_ENDPOINT=/oauth2/v2.0/token
      # The claim name you want to map to the unique ID field:
      #- OAUTH2_ID_MAP=email
      # The claim name you want to map to the username field:
      #- OAUTH2_USERNAME_MAP=email
      # The claim name you want to map to the full name field:
      #- OAUTH2_FULLNAME_MAP=name
      # Tthe claim name you want to map to the email field:
      #- OAUTH2_EMAIL_MAP=email
      #-----------------------------------------------------------------
      # ==== OAUTH2 KEYCLOAK ====
      # https://github.com/wekan/wekan/wiki/Keycloak  <== MAPPING INFO, REQUIRED
      #- OAUTH2_ENABLED=true
      # OAuth2 login style: popup or redirect.
      #- OAUTH2_LOGIN_STYLE=redirect
      #- OAUTH2_CLIENT_ID=<Keycloak create Client ID>
      #- OAUTH2_SERVER_URL=<Keycloak server name>/auth
      #- OAUTH2_AUTH_ENDPOINT=/realms/<keycloak realm>/protocol/openid-connect/auth
      #- OAUTH2_USERINFO_ENDPOINT=/realms/<keycloak realm>/protocol/openid-connect/userinfo
      #- OAUTH2_TOKEN_ENDPOINT=/realms/<keycloak realm>/protocol/openid-connect/token
      #- OAUTH2_SECRET=<keycloak client secret>
      #-----------------------------------------------------------------
      # ==== OAUTH2 DOORKEEPER ====
      # https://github.com/wekan/wekan/issues/1874
      # https://github.com/wekan/wekan/wiki/OAuth2
      # Enable the OAuth2 connection
      #- OAUTH2_ENABLED=true
      # OAuth2 docs: https://github.com/wekan/wekan/wiki/OAuth2
      # OAuth2 login style: popup or redirect.
      #- OAUTH2_LOGIN_STYLE=redirect
      # OAuth2 Client ID.
      #- OAUTH2_CLIENT_ID=abcde12345
      # OAuth2 Secret.
      #- OAUTH2_SECRET=54321abcde
      # OAuth2 Server URL.
      #- OAUTH2_SERVER_URL=https://chat.example.com
      # OAuth2 Authorization Endpoint.
      #- OAUTH2_AUTH_ENDPOINT=/oauth/authorize
      # OAuth2 Userinfo Endpoint.
      #- OAUTH2_USERINFO_ENDPOINT=/oauth/userinfo
      # OAuth2 Token Endpoint.
      #- OAUTH2_TOKEN_ENDPOINT=/oauth/token
      # OAUTH2 ID Token Whitelist Fields.
      #- OAUTH2_ID_TOKEN_WHITELIST_FIELDS=""
      # OAUTH2 Request Permissions.
      #- OAUTH2_REQUEST_PERMISSIONS=openid profile email
      # OAuth2 ID Mapping
      #- OAUTH2_ID_MAP=
      # OAuth2 Username Mapping
      #- OAUTH2_USERNAME_MAP=
      # OAuth2 Fullname Mapping
      #- OAUTH2_FULLNAME_MAP=
      # OAuth2 Email Mapping
      #- OAUTH2_EMAIL_MAP=
      #-----------------------------------------------------------------
      # ==== LDAP: UNCOMMENT ALL TO ENABLE LDAP ====
      # https://github.com/wekan/wekan/wiki/LDAP
      # For Snap settings see https://github.com/wekan/wekan-snap/wiki/Supported-settings-keys
      # Most settings work both on Snap and Docker below.
      # Note: Do not add single quotes '' to variables. Having spaces still works without quotes where required.
      #
      # The default authentication method used if a user does not exist to create and authenticate. Can be set as ldap.
      - DEFAULT_AUTHENTICATION_METHOD=ldap
      #
      # Enable or not the connection by the LDAP
      - LDAP_ENABLE=true
      #
      # The port of the LDAP server
      - LDAP_PORT=389
      #
      # The host server for the LDAP server
      - LDAP_HOST=dc.mydomain.com
      #
      # The base DN for the LDAP Tree
      - LDAP_BASEDN=ou=******,ou=******,dc=mydomain,dc=com
      #
      # Fallback on the default authentication method
      #- LDAP_LOGIN_FALLBACK=false
      #
      # Reconnect to the server if the connection is lost
      #- LDAP_RECONNECT=true
      #
      # Overall timeout, in milliseconds
      #- LDAP_TIMEOUT=10000
      #
      # Specifies the timeout for idle LDAP connections in milliseconds
      #- LDAP_IDLE_TIMEOUT=10000
      #
      # Connection timeout, in milliseconds
      #- LDAP_CONNECT_TIMEOUT=10000
      #
      # If the LDAP needs a user account to search
      - LDAP_AUTHENTIFICATION=true
      #
      # The search user DN
      - LDAP_AUTHENTIFICATION_USERDN=CN=ldapserviceaccount,OU=*******,OU=*******,OU=******,DC=mydomain,DC=com
      #
      # The password for the search user
      - LDAP_AUTHENTIFICATION_PASSWORD=ThisIsTheCorrectPassword
      #
      # Enable logs for the module
      - LDAP_LOG_ENABLED=true
      #
      # If the sync of the users should be done in the background
      #- LDAP_BACKGROUND_SYNC=false
      #
      # At which interval does the background task sync in milliseconds.
      # Leave this unset, so it uses default, and does not crash.
      # https://github.com/wekan/wekan/issues/2354#issuecomment-515305722
      - LDAP_BACKGROUND_SYNC_INTERVAL=''
      #
      #- LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED=false
      #
      #- LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS=false
      #
      # If using LDAPS: LDAP_ENCRYPTION=ssl
      #- LDAP_ENCRYPTION=false
      #
      # The certification for the LDAPS server. Certificate needs to be included in this docker-compose.yml file.
      #- LDAP_CA_CERT=-----BEGIN CERTIFICATE-----MIIE+G2FIdAgIC...-----END CERTIFICATE-----
      #
      # Reject Unauthorized Certificate
      #- LDAP_REJECT_UNAUTHORIZED=false
      #
      # Option to login to the LDAP server with the user's own username and password, instead of an administrator key. Default: false (use administrator key).
      #- LDAP_USER_AUTHENTICATION="true"
      #
      # Which field is used to find the user for the user authentication. Default: uid.
      #- LDAP_USER_AUTHENTICATION_FIELD="uid"
      #
      # Optional extra LDAP filters. Don't forget the outmost enclosing parentheses if needed
      #- LDAP_USER_SEARCH_FILTER=
      #
      # base (search only in the provided DN), one (search only in the provided DN and one level deep), or sub (search the whole subtree)
      #- LDAP_USER_SEARCH_SCOPE=one
      #
      # Which field is used to find the user, like uid / sAMAccountName
      - LDAP_USER_SEARCH_FIELD=sAMAccountName
      #
      # Used for pagination (0=unlimited)
      #- LDAP_SEARCH_PAGE_SIZE=0
      #
      # The limit number of entries (0=unlimited)
      #- LDAP_SEARCH_SIZE_LIMIT=0
      #
      # Enable group filtering
      #- LDAP_GROUP_FILTER_ENABLE=false
      #
      # The object class for filtering. Example: group
      #- LDAP_GROUP_FILTER_OBJECTCLASS=
      #
      #- LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE=
      #
      #- LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE=
      #
      #- LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT=
      #
      #- LDAP_GROUP_FILTER_GROUP_NAME=
      #
      # LDAP_UNIQUE_IDENTIFIER_FIELD : This field is sometimes class GUID (Globally Unique Identifier). Example: guid
      #- LDAP_UNIQUE_IDENTIFIER_FIELD=
      #
      # LDAP_UTF8_NAMES_SLUGIFY : Convert the username to utf8
      #- LDAP_UTF8_NAMES_SLUGIFY=true
      #
      # LDAP_USERNAME_FIELD : Which field contains the ldap username. username / sAMAccountName
      - LDAP_USERNAME_FIELD=sAMAccountName
      #
      # LDAP_FULLNAME_FIELD : Which field contains the ldap fullname. fullname / sAMAccountName
      - LDAP_FULLNAME_FIELD=cn
      #
      #- LDAP_MERGE_EXISTING_USERS=false
      #
      # Allow existing account matching by e-mail address when username does not match
      #- LDAP_EMAIL_MATCH_ENABLE=true
      #
      # LDAP_EMAIL_MATCH_REQUIRE : require existing account matching by e-mail address when username does match
      #- LDAP_EMAIL_MATCH_REQUIRE=true
      #
      # LDAP_EMAIL_MATCH_VERIFIED : require existing account email address to be verified for matching
      #- LDAP_EMAIL_MATCH_VERIFIED=true
      #
      # LDAP_EMAIL_FIELD : which field contains the LDAP e-mail address
      #- LDAP_EMAIL_FIELD=mail
      #-----------------------------------------------------------------
      #- LDAP_SYNC_USER_DATA=false
      #
      #- LDAP_SYNC_USER_DATA_FIELDMAP={"cn":"name", "mail":"email"}
      #
      - LDAP_SYNC_GROUP_ROLES=''
      #
      # The default domain of the ldap it is used to create email if the field is not map correctly with the LDAP_SYNC_USER_DATA_FIELDMAP
      # example :
      #- LDAP_DEFAULT_DOMAIN=mydomain.com
      #
      # Enable/Disable syncing of admin status based on ldap groups:
      - LDAP_SYNC_ADMIN_STATUS=true
      #
      # Comma separated list of admin group names to sync.
      - LDAP_SYNC_ADMIN_GROUPS=*******
      #---------------------------------------------------------------------
      # Login to LDAP automatically with HTTP header.
      # In below example for siteminder, at right side of = is header name.
      #- HEADER_LOGIN_ID=HEADERUID
      #- HEADER_LOGIN_FIRSTNAME=HEADERFIRSTNAME
      #- HEADER_LOGIN_LASTNAME=HEADERLASTNAME
      #- HEADER_LOGIN_EMAIL=HEADEREMAILADDRESS
      #---------------------------------------------------------------------
      # ==== LOGOUT TIMER, probably does not work yet ====
      # LOGOUT_WITH_TIMER : Enables or not the option logout with timer
      # example : LOGOUT_WITH_TIMER=true
      #- LOGOUT_WITH_TIMER=
      #
      # LOGOUT_IN : The number of days
      # example : LOGOUT_IN=1
      #- LOGOUT_IN=
      #
      # LOGOUT_ON_HOURS : The number of hours
      # example : LOGOUT_ON_HOURS=9
      #- LOGOUT_ON_HOURS=
      #
      # LOGOUT_ON_MINUTES : The number of minutes
      # example : LOGOUT_ON_MINUTES=55
      #- LOGOUT_ON_MINUTES=
      #-------------------------------------------------------------------

    depends_on:
      - wekandb

#---------------------------------------------------------------------------------
# ==== OPTIONAL: SHARE DATABASE TO OFFICE LAN AND REMOTE VPN ====
#  When using Wekan both at office LAN and remote VPN:
#    1) Have above Wekan docker container config with LAN IP address
#    2) Copy all of above wekan container config below, look above of this part above and all config below it,
#       before above depends_on: part:
#
#         wekan:
#            #-------------------------------------------------------------------------------------
#            # ==== MONGODB AND METEOR VERSION ====
#            # a) For Wekan Meteor 1.8.x version at meteor-1.8 branch, .....
#
#
#       and change name to different name like wekan2 or wekanvpn, and change ROOT_URL to server VPN IP
#       address.
#    3) This way both Wekan containers can use same MongoDB database
#       and see the same Wekan boards.
#    4) You could also add 3rd Wekan container for 3rd network etc.
# EXAMPLE:
#  wekan2:
#    ....COPY CONFIG FROM ABOVE TO HERE...
#    environment:
#      - ROOT_URL='http://10.10.10.10'
#      ...COPY CONFIG FROM ABOVE TO HERE...
#---------------------------------------------------------------------------------

# OPTIONAL NGINX CONFIG FOR REVERSE PROXY
#  nginx:
#    image: nginx
#    container_name: nginx
#    restart: always
#    networks:
#      - wekan-tier
#    depends_on:
#      - wekan
#    ports:
#      - 80:80
#      - 443:443
#    volumes:
#      - ./nginx/ssl:/etc/nginx/ssl/:ro
#      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
## Alternative volume config:
##   volumes:
##     - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
##     - ./nginx/ssl/ssl.conf:/etc/nginx/conf.d/ssl/ssl.conf:ro
##     - ./nginx/ssl/testvm-ehu.crt:/etc/nginx/conf.d/ssl/certs/mycert.crt:ro
##     - ./nginx/ssl/testvm-ehu.key:/etc/nginx/conf.d/ssl/certs/mykey.key:ro
##     - ./nginx/ssl/pphrase:/etc/nginx/conf.d/ssl/pphrase:ro
networks:
  reverse-proxy:
    external:
      name: reverse-proxy
bkraul commented 4 years ago

This is yet another example of the fact that LDAP is operating properly, as you can see, the user was synced correctly with all it's info, even the admin flag. But somehow, it just can't get logged into the actual wekan instance.:

image

xet7 commented 4 years ago

When using LDAP or OIDC, you login with your email address.

For example: username: user@example.com password: password

bkraul commented 4 years ago

This has been discussed before in this issue. That does not seem to be accurate: login

As you can see from previous log outputs, when not using the email as the login, the LDAP authentication is taking place, and the user is being found. However, as you can see from this output, that is not the case when using email as you are pointing out:

[DEBUG] connectionOptions{ url: 'ldap://dc.mydomain.com:389',,
  timeout: 10000,,
  connectTimeout: 10000,,
  idleTimeout: 10000,,
  reconnect: true,,
  log: ,
   Logger {,
     domain: null,,
     _events: {},,
     _eventsCount: 0,,
     _maxListeners: undefined,,
     _level: 30,,
     streams: [ [Object] ],,
     serializers: null,,
     fields: ,
     src: false,,
      { name: 'ldapjs',,
        component: 'client',,
        hostname: '8bba8d147366',,
        pid: 1 } } } ,
[INFO] LDAP connected ,
[INFO] Binding UserDN "cn=ldapserviceaccount,ou=******,ou=******,ou=********,dc=mydomain,dc=com",
[DEBUG] searchOptions {,
[INFO] Searching user "bkraul@epgins.com",
  "filter": "(&(sAMAccountName=bkraul@epgins.com))",,
  "scope": "sub",,
  "sizeLimit": 0,
[DEBUG] BaseDN "ou=*****,ou=*******,dc=mydomain,dc=com",
},
[INFO] Search result count ,
[INFO] Search returned ,
[ERROR] Error: User not Found ,

The email address "is" the correct email address for the account.

xet7 commented 4 years ago

You can try commenting out # these in your config:

- LDAP_BACKGROUND_SYNC_INTERVAL=''
- LDAP_SYNC_GROUP_ROLES=''
- LDAP_SYNC_ADMIN_STATUS=true
- LDAP_SYNC_ADMIN_GROUPS=*******
bkraul commented 4 years ago

OK. So I commented the 4 vars you recommended, and I successfully logged in. Then, out of curiosity, I un-commented all but the - LDAP_SYNC_ADMIN_STATUS=true var, and it also worked successfully (again, email address is not needed), with the following log message:

[INFO] LDAP connected ,
[INFO] Binding UserDN "cn=ldapserviceaccount,ou=*******,ou=*****,ou=******,dc=mydomaindc=com",
[INFO] Searching user "bkraul",
[DEBUG] searchOptions {,
  "scope": "sub",,
  "sizeLimit": 0,
[DEBUG] BaseDN "ou=*****,ou=******,dc=mydomain,dc=com",
[INFO] Search result count 1,
},
[INFO] Authenticating "CN=Belman Kraul,OU=****,OU=*****,OU=*****,DC=mydomain,DC=com",
[INFO] Authenticated "CN=Belman Kraul,OU=***,OU=*******,OU=*****,DC=mydomain,DC=com",
[DEBUG] Identifying user with: sAMAccountName ,
[INFO] Querying user ,
[DEBUG] userQuery {,
  "services.ldap.id": "626b7261756c",
[INFO] Logging user ,
[INFO] Syncing user data ,
[DEBUG] user {,
  "_id": "Xuyp3HZNTGTzXoXPb",
[DEBUG] fullname= "Belman Kraul",
[INFO] Syncing user fullname: "Belman Kraul",

So it would be safe to assume that the process that syncs the LDAP admin status to the wekan user admin flag is not working correctly, as shown by the output:

[INFO] Logging user 
[DEBUG] Updating admin status 
Exception while invoking method 'login' [object Object]
bkraul commented 4 years ago

I suppose that for the time being I can live without that feature, as what was of utmost importance to me was to not lose the existing wekan data for my domain users, which seems achieved now, but I am curious as to what is going on there. Thanks for your help so far.

xet7 commented 4 years ago

That LDAP_SYNC_ADMIN_STATUS does require LDAP_SYNC_ADMIN_GROUPS=******* so maybe it is that LDAP_SYNC_ADMIN_GROUPS does expect many groups separated by , and does not handle correctly just one group? https://github.com/wekan/wekan/blob/master/packages/wekan-ldap/server/loginHandler.js#L184

@Akuket

What do you think?

bkraul commented 4 years ago

I added a couple of dummy groups to the list, such:

- LDAP_SYNC_ADMIN_GROUPS=Domain Admins,dummy1,dummy2

The result is the same. Not sure if I am missing any quotes or anything like that to account for the space in one of the groups.

bkraul commented 4 years ago

I am not well-versed in node.js, but a simple javascript split operation returns result of the split as:

 […]
​0: "Domain Admins"
​1: "dummy1"
​2: "dummy2"
​length: 3
Akuket commented 4 years ago

If you can try in dev environment (clone repo and start with meteor), you could add a file debug.js in the server folder with this content.

import { inspect } from "util";

Meteor.startup(() => {
  if (Meteor.isServer) {
    const originalMeteorDebug = Meteor._debug;
    Meteor._debug = function (message, stack) {
      console.log('===== message =====', message);
      console.log('===== stack =====', stack);
      console.log(inspect(stack, {
        showHidden: true,
        depth: null,
        maxArrayLength: null,
      }));
      return originalMeteorDebug.apply(this, arguments);
    };
  }
});

If all works, you will see the content of the exception object.

bkraul commented 4 years ago

Well, that's the, issue, I would do that but I do not develop in meteor, therefore I have no idea how to set up a meteor dev-env, though I am trying. But I was hopeful there would be a logging option that would return this when using the wekan docker image, which is what I am using.

timmy-mac commented 4 years ago

I have got the exact same behaviour in the snap version of Wekan. LDAP login successful (and new users created in Wekan) but:

Exception while invoking method 'login' [object Object]

I would love to apply the workaround and comment out the offending variable but I'm not sure how/where to do so because I don't set the variables by editing a file but on the command line like so:

sudo snap set wekan ldap-sync-admin-status='false'

Is there some way I can get rid of this variable entirely?

Thanks, Tim

xet7 commented 4 years ago

@timmy-mac

Yes:

sudo snap set wekan ldap-sync-admin-status=''

Or alternatively:

sudo snap unset wekan ldap-sync-admin-status

That way there is no Object error, and sync works.

Yes, I should remove this setting sometime.

sternma commented 2 weeks ago

Hi @xet7 , I want to bump this issue as I am still seeing it in the latest version 7.49. Same exact symptoms as above, except the error is as follows:

[DEBUG] Updating admin status
Exception while invoking method 'login' TypeError: ldap.getUserGroups(...).filter is not a function
    at MethodInvocation.<anonymous> (packages/wekan-ldap/server/loginHandler.js:185:61)
    at MethodInvocation.<anonymous> (packages/meteor.js:365:18)
    at packages/accounts-base/accounts_server.js:589:31
    at /build/programs/server/npm/node_modules/meteor/promise/node_modules/meteor-promise/fiber_pool.js:43:40
 => awaited here:
    at Function.Promise.await (/build/programs/server/npm/node_modules/meteor/promise/node_modules/meteor-promise/promise_server.js:56:12)
    at packages/accounts-base/accounts_server.js:1533:11
    at /build/programs/server/npm/node_modules/meteor/promise/node_modules/meteor-promise/fiber_pool.js:43:40
 => awaited here:
    at Function.Promise.await (/build/programs/server/npm/node_modules/meteor/promise/node_modules/meteor-promise/promise_server.js:56:12)
    at packages/accounts-base/accounts_server.js:653:7
    at /build/programs/server/npm/node_modules/meteor/promise/node_modules/meteor-promise/fiber_pool.js:43:40
 => awaited here:
    at Function.Promise.await (/build/programs/server/npm/node_modules/meteor/promise/node_modules/meteor-promise/promise_server.js:56:12)
    at packages/meteor.js:367:22
    at Meteor.EnvironmentVariable.EVp.withValue (packages/meteor.js:1389:31)
    at Object._failIfArgumentsAreNotAllChecked (packages/check/match.js:116:43)
    at maybeAuditArgumentChecks (packages/ddp-server/livedata_server.js:1935:18)
    at getCurrentMethodInvocationResult (packages/ddp-server/livedata_server.js:808:38)
    at packages/meteor.js:365:18
    at Meteor.EnvironmentVariable.EVp.withValue (packages/meteor.js:1389:31)
    at packages/ddp-server/livedata_server.js:827:46
    at new Promise (<anonymous>)
    at Session.method (packages/ddp-server/livedata_server.js:775:23)
    at packages/ddp-server/livedata_server.js:639:43