Explorar el Código

add ldap support | simplify authentications

guillaume hace 6 años
padre
commit
3b4f285fea

+ 81 - 1
Dockerfile

@@ -18,12 +18,52 @@ ARG MATOMO_WITH_USERNAME
 ARG BROWSER_POLICY_ENABLED
 ARG BROWSER_POLICY_ENABLED
 ARG TRUSTED_URL
 ARG TRUSTED_URL
 ARG WEBHOOKS_ATTRIBUTES
 ARG WEBHOOKS_ATTRIBUTES
+ARG OAUTH2_ENABLED
 ARG OAUTH2_CLIENT_ID
 ARG OAUTH2_CLIENT_ID
 ARG OAUTH2_SECRET
 ARG OAUTH2_SECRET
 ARG OAUTH2_SERVER_URL
 ARG OAUTH2_SERVER_URL
 ARG OAUTH2_AUTH_ENDPOINT
 ARG OAUTH2_AUTH_ENDPOINT
 ARG OAUTH2_USERINFO_ENDPOINT
 ARG OAUTH2_USERINFO_ENDPOINT
 ARG OAUTH2_TOKEN_ENDPOINT
 ARG OAUTH2_TOKEN_ENDPOINT
+ARG LDAP_ENABLE
+ARG LDAP_PORT
+ARG LDAP_HOST
+ARG LDAP_BASEDN
+ARG LDAP_LOGIN_FALLBACK
+ARG LDAP_RECONNECT
+ARG LDAP_TIMEOUT
+ARG LDAP_IDLE_TIMEOUT
+ARG LDAP_CONNECT_TIMEOUT
+ARG LDAP_AUTHENTIFICATION
+ARG LDAP_AUTHENTIFICATION_USERDN
+ARG LDAP_AUTHENTIFICATION_PASSWORD
+ARG LDAP_LOG_ENABLED
+ARG LDAP_BACKGROUND_SYNC
+ARG LDAP_BACKGROUND_SYNC_INTERVAL
+ARG LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED
+ARG LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS
+ARG LDAP_ENCRYPTION
+ARG LDAP_CA_CERT
+ARG LDAP_REJECT_UNAUTHORIZED
+ARG LDAP_USER_SEARCH_FILTER
+ARG LDAP_USER_SEARCH_SCOPE
+ARG LDAP_USER_SEARCH_FIELD
+ARG LDAP_SEARCH_PAGE_SIZE
+ARG LDAP_SEARCH_SIZE_LIMIT
+ARG LDAP_GROUP_FILTER_ENABLE
+ARG LDAP_GROUP_FILTER_OBJECTCLASS
+ARG LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE
+ARG LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE
+ARG LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT
+ARG LDAP_GROUP_FILTER_GROUP_NAME
+ARG LDAP_UNIQUE_IDENTIFIER_FIELD
+ARG LDAP_UTF8_NAMES_SLUGIFY
+ARG LDAP_USERNAME_FIELD
+ARG LDAP_MERGE_EXISTING_USERS
+ARG LDAP_SYNC_USER_DATA
+ARG LDAP_SYNC_USER_DATA_FIELDMAP
+ARG LDAP_SYNC_GROUP_ROLES
+ARG LDAP_DEFAULT_DOMAIN
 
 
 # Set the environment variables (defaults where required)
 # Set the environment variables (defaults where required)
 # DOES NOT WORK: paxctl fix for alpine linux: https://github.com/wekan/wekan/issues/1303
 # DOES NOT WORK: paxctl fix for alpine linux: https://github.com/wekan/wekan/issues/1303
@@ -45,12 +85,52 @@ ENV BUILD_DEPS="apt-utils bsdtar gnupg gosu wget curl bzip2 build-essential pyth
     BROWSER_POLICY_ENABLED=true \
     BROWSER_POLICY_ENABLED=true \
     TRUSTED_URL="" \
     TRUSTED_URL="" \
     WEBHOOKS_ATTRIBUTES="" \
     WEBHOOKS_ATTRIBUTES="" \
+    OAUTH2_ENABLED=false \
     OAUTH2_CLIENT_ID="" \
     OAUTH2_CLIENT_ID="" \
     OAUTH2_SECRET="" \
     OAUTH2_SECRET="" \
     OAUTH2_SERVER_URL="" \
     OAUTH2_SERVER_URL="" \
     OAUTH2_AUTH_ENDPOINT="" \
     OAUTH2_AUTH_ENDPOINT="" \
     OAUTH2_USERINFO_ENDPOINT="" \
     OAUTH2_USERINFO_ENDPOINT="" \
-    OAUTH2_TOKEN_ENDPOINT=""
+    OAUTH2_TOKEN_ENDPOINT="" \
+    LDAP_ENABLE=false \
+    LDAP_PORT=389 \
+    LDAP_HOST="" \
+    LDAP_BASEDN="" \
+    LDAP_LOGIN_FALLBACK=false \
+    LDAP_RECONNECT=true \
+    LDAP_TIMEOUT=10000 \
+    LDAP_IDLE_TIMEOUT=10000 \
+    LDAP_CONNECT_TIMEOUT=10000 \
+    LDAP_AUTHENTIFICATION=false \
+    LDAP_AUTHENTIFICATION_USERDN="" \
+    LDAP_AUTHENTIFICATION_PASSWORD="" \
+    LDAP_LOG_ENABLED=false \
+    LDAP_BACKGROUND_SYNC=false \
+    LDAP_BACKGROUND_SYNC_INTERVAL=100 \
+    LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED=false \
+    LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS=false \
+    LDAP_ENCRYPTION=false \
+    LDAP_CA_CERT="" \
+    LDAP_REJECT_UNAUTHORIZED=false \
+    LDAP_USER_SEARCH_FILTER="" \
+    LDAP_USER_SEARCH_SCOPE="" \
+    LDAP_USER_SEARCH_FIELD="" \
+    LDAP_SEARCH_PAGE_SIZE=0 \
+    LDAP_SEARCH_SIZE_LIMIT=0 \
+    LDAP_GROUP_FILTER_ENABLE=false \
+    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="" \
+    LDAP_UTF8_NAMES_SLUGIFY=true \
+    LDAP_USERNAME_FIELD="" \
+    LDAP_MERGE_EXISTING_USERS=false \
+    LDAP_SYNC_USER_DATA=false \
+    LDAP_SYNC_USER_DATA_FIELDMAP="" \
+    LDAP_SYNC_GROUP_ROLES="" \
+    LDAP_DEFAULT_DOMAIN="" \
 
 
 # Copy the app to the image
 # Copy the app to the image
 COPY ${SRC_PATH} /home/wekan/app
 COPY ${SRC_PATH} /home/wekan/app

+ 32 - 16
client/components/main/layouts.js

@@ -6,7 +6,23 @@ const i18nTagToT9n = (i18nTag) => {
   return i18nTag;
   return i18nTag;
 };
 };
 
 
+const validator = {
+  set: function(obj, prop, value) {
+    if (prop === 'state' && value !== 'signIn') {
+      $('.at-form-authentication').hide();
+    } else if (prop === 'state' && value === 'signIn') {
+      $('.at-form-authentication').show();
+    }
+    // The default behavior to store the value
+    obj[prop] = value;
+    // Indicate success
+    return true;
+  }
+};
+
 Template.userFormsLayout.onRendered(() => {
 Template.userFormsLayout.onRendered(() => {
+  AccountsTemplates.state.form.keys = new Proxy(AccountsTemplates.state.form.keys, validator);
+
   const i18nTag = navigator.language;
   const i18nTag = navigator.language;
   if (i18nTag) {
   if (i18nTag) {
     T9n.setLanguage(i18nTagToT9n(i18nTag));
     T9n.setLanguage(i18nTagToT9n(i18nTag));
@@ -65,37 +81,37 @@ Template.userFormsLayout.events({
       }
       }
     });
     });
   },
   },
-  'submit form'(event) {
-    const connectionMethod = $('.select-connection').val();
-
+  'click #at-btn'(event) {
+    /* All authentication method can be managed/called here. 
+       !! DON'T FORGET to correctly fill the fields of the user during its creation if necessary authenticationMethod : String !!
+    */
+    const authenticationMethodSelected = $('.select-authentication').val();
     // Local account
     // Local account
-    if (connectionMethod === 'default') {
+    if (authenticationMethodSelected === 'password') {
       return;
       return;
     }
     }
 
 
-    // TODO : find a way to block "submit #at-pwd-form" of the at_pwd_form.js
+    // Stop submit #at-pwd-form
+    event.preventDefault();
+    event.stopImmediatePropagation();
 
 
-    const inputs = event.target.getElementsByTagName('input');
-
-    const email = inputs.namedItem('at-field-username_and_email').value;
-    const password = inputs.namedItem('at-field-password').value;
+    const email = $('#at-field-username_and_email').val();
+    const password = $('#at-field-password').val();
 
 
     // Ldap account
     // Ldap account
-    if (connectionMethod === 'ldap') {
+    if (authenticationMethodSelected === 'ldap') {
       // Check if the user can use the ldap connection
       // Check if the user can use the ldap connection
-      Meteor.subscribe('user-connection-method', email, {
+      Meteor.subscribe('user-authenticationMethod', email, {
         onReady() {
         onReady() {
-          const ldap = Users.findOne();
-
-          if (ldap) {
+          const user = Users.findOne();
+          if (user === undefined || user.authenticationMethod === 'ldap') {
             // Use the ldap connection package
             // Use the ldap connection package
             Meteor.loginWithLDAP(email, password, function(error) {
             Meteor.loginWithLDAP(email, password, function(error) {
               if (!error) {
               if (!error) {
                 // Connection
                 // Connection
                 return FlowRouter.go('/');
                 return FlowRouter.go('/');
-              } else {
-                return error;
               }
               }
+              return error;
             });
             });
           }
           }
           return this.stop();
           return this.stop();

+ 4 - 4
client/components/settings/connectionMethod.jade

@@ -1,6 +1,6 @@
 template(name='connectionMethod')
 template(name='connectionMethod')
-  div.at-form-connection
-    label Authentication method
-    select.select-connection
-        each connections
+  div.at-form-authentication
+    label {{_ 'authentication-method'}}
+    select.select-authentication
+        each authentications
             option(value="{{value}}") {{_ value}}
             option(value="{{value}}") {{_ value}}

+ 11 - 11
client/components/settings/connectionMethod.js

@@ -1,20 +1,20 @@
 Template.connectionMethod.onCreated(function() {
 Template.connectionMethod.onCreated(function() {
-  this.connectionMethods = new ReactiveVar([]);
+  this.authenticationMethods = new ReactiveVar([]);
 
 
-  Meteor.call('getConnectionsEnabled', (_, result) => {
+  Meteor.call('getAuthenticationsEnabled', (_, result) => {
     if (result) {
     if (result) {
       // TODO : add a management of different languages
       // TODO : add a management of different languages
       // (ex {value: ldap, text: TAPi18n.__('ldap', {}, T9n.getLanguage() || 'en')})
       // (ex {value: ldap, text: TAPi18n.__('ldap', {}, T9n.getLanguage() || 'en')})
-      this.connectionMethods.set([
-        {value: 'default'},
-        // Gets only the connection methods availables
+      this.authenticationMethods.set([
+        {value: 'password'},
+        // Gets only the authentication methods availables
         ...Object.entries(result).filter((e) => e[1]).map((e) => ({value: e[0]})),
         ...Object.entries(result).filter((e) => e[1]).map((e) => ({value: e[0]})),
       ]);
       ]);
     }
     }
 
 
     // If only the default authentication available, hides the select boxe
     // If only the default authentication available, hides the select boxe
-    const content = $('.at-form-connection');
-    if (!(this.connectionMethods.get().length > 1)) {
+    const content = $('.at-form-authentication');
+    if (!(this.authenticationMethods.get().length > 1)) {
       content.hide();
       content.hide();
     } else {
     } else {
       content.show();
       content.show();
@@ -24,11 +24,11 @@ Template.connectionMethod.onCreated(function() {
 
 
 Template.connectionMethod.onRendered(() => {
 Template.connectionMethod.onRendered(() => {
   // Moves the select boxe in the first place of the at-pwd-form div
   // Moves the select boxe in the first place of the at-pwd-form div
-  $('.at-form-connection').detach().prependTo('.at-pwd-form');
+  $('.at-form-authentication').detach().prependTo('.at-pwd-form');
 });
 });
 
 
 Template.connectionMethod.helpers({
 Template.connectionMethod.helpers({
-  connections() {
-    return Template.instance().connectionMethods.get();
+  authentications() {
+    return Template.instance().authenticationMethods.get();
   },
   },
-});
+});

+ 19 - 3
client/components/settings/peopleBody.jade

@@ -27,6 +27,7 @@ template(name="peopleGeneral")
         th {{_ 'verified'}}
         th {{_ 'verified'}}
         th {{_ 'createdAt'}}
         th {{_ 'createdAt'}}
         th {{_ 'active'}}
         th {{_ 'active'}}
+        th {{_ 'authentication-method'}}
         th
         th
       each user in peopleList
       each user in peopleList
         +peopleRow(userId=user._id)
         +peopleRow(userId=user._id)
@@ -52,6 +53,7 @@ template(name="peopleRow")
         | {{_ 'no'}}
         | {{_ 'no'}}
       else
       else
         | {{_ 'yes'}}
         | {{_ 'yes'}}
+    td {{_ userData.authenticationMethod }}
     td
     td
       a.edit-user
       a.edit-user
         | {{_ 'edit'}}
         | {{_ 'edit'}}
@@ -66,12 +68,18 @@ template(name="editUserPopup")
       | {{_ 'username'}}
       | {{_ 'username'}}
       span.error.hide.username-taken
       span.error.hide.username-taken
         | {{_ 'error-username-taken'}}
         | {{_ 'error-username-taken'}}
-      input.js-profile-username(type="text" value=user.username)
+      if isLdap
+        input.js-profile-username(type="text" value=user.username readonly)
+      else
+        input.js-profile-username(type="text" value=user.username)
     label
     label
       | {{_ 'email'}}
       | {{_ 'email'}}
       span.error.hide.email-taken
       span.error.hide.email-taken
         | {{_ 'error-email-taken'}}
         | {{_ 'error-email-taken'}}
-      input.js-profile-email(type="email" value="{{user.emails.[0].address}}")
+      if isLdap
+        input.js-profile-email(type="email" value="{{user.emails.[0].address}}" readonly)
+      else
+        input.js-profile-email(type="email" value="{{user.emails.[0].address}}")
     label
     label
       | {{_ 'admin'}}
       | {{_ 'admin'}}
       select.select-role.js-profile-isadmin
       select.select-role.js-profile-isadmin
@@ -82,9 +90,17 @@ template(name="editUserPopup")
       select.select-active.js-profile-isactive
       select.select-active.js-profile-isactive
         option(value="false") {{_ 'yes'}}
         option(value="false") {{_ 'yes'}}
         option(value="true" selected="{{user.loginDisabled}}") {{_ 'no'}}
         option(value="true" selected="{{user.loginDisabled}}") {{_ 'no'}}
+    label
+      | {{_ 'authentication-type'}}
+      select.select-authenticationMethod.js-authenticationMethod
+        each authentications
+          if isSelected value
+            option(value="{{value}}" selected) {{_ value}}
+          else
+            option(value="{{value}}") {{_ value}}
     hr
     hr
     label
     label
       | {{_ 'password'}}
       | {{_ 'password'}}
       input.js-profile-password(type="password")
       input.js-profile-password(type="password")
 
 
-    input.primary.wide(type="submit" value="{{_ 'save'}}")
+    input.primary.wide(type="submit" value="{{_ 'save'}}")

+ 31 - 0
client/components/settings/peopleBody.js

@@ -62,10 +62,39 @@ Template.peopleRow.helpers({
   },
   },
 });
 });
 
 
+Template.editUserPopup.onCreated(function() {
+  this.authenticationMethods = new ReactiveVar([]);
+
+  Meteor.call('getAuthenticationsEnabled', (_, result) => {
+    if (result) {
+      // TODO : add a management of different languages 
+      // (ex {value: ldap, text: TAPi18n.__('ldap', {}, T9n.getLanguage() || 'en')})
+      this.authenticationMethods.set([
+        {value: 'password'},
+        // Gets only the authentication methods availables
+        ...Object.entries(result).filter(e => e[1]).map(e => ({value: e[0]})),
+      ]);
+    }
+  });
+});
+
 Template.editUserPopup.helpers({
 Template.editUserPopup.helpers({
   user() {
   user() {
     return Users.findOne(this.userId);
     return Users.findOne(this.userId);
   },
   },
+  authentications() {
+    return Template.instance().authenticationMethods.get();
+  },
+  isSelected(match) {
+    const userId = Template.instance().data.userId;
+    const selected = Users.findOne(userId).authenticationMethod;
+    return selected === match;
+  },
+  isLdap() {
+    const userId = Template.instance().data.userId;
+    const selected = Users.findOne(userId).authenticationMethod;
+    return selected === 'ldap';
+  }
 });
 });
 
 
 BlazeComponent.extendComponent({
 BlazeComponent.extendComponent({
@@ -91,6 +120,7 @@ Template.editUserPopup.events({
     const isAdmin = tpl.find('.js-profile-isadmin').value.trim();
     const isAdmin = tpl.find('.js-profile-isadmin').value.trim();
     const isActive = tpl.find('.js-profile-isactive').value.trim();
     const isActive = tpl.find('.js-profile-isactive').value.trim();
     const email = tpl.find('.js-profile-email').value.trim();
     const email = tpl.find('.js-profile-email').value.trim();
+    const authentication = tpl.find('.js-authenticationMethod').value.trim();
 
 
     const isChangePassword = password.length > 0;
     const isChangePassword = password.length > 0;
     const isChangeUserName = username !== user.username;
     const isChangeUserName = username !== user.username;
@@ -101,6 +131,7 @@ Template.editUserPopup.events({
         'profile.fullname': fullname,
         'profile.fullname': fullname,
         'isAdmin': isAdmin === 'true',
         'isAdmin': isAdmin === 'true',
         'loginDisabled': isActive === 'true',
         'loginDisabled': isActive === 'true',
+        'authenticationMethod': authentication
       },
       },
     });
     });
 
 

+ 121 - 0
docker-compose.yml

@@ -63,6 +63,9 @@ services:
       # What to send to Outgoing Webhook, or leave out. Example, that includes all that are default: cardId,listId,oldListId,boardId,comment,user,card,commentId .
       # What to send to Outgoing Webhook, or leave out. Example, that includes all that are default: cardId,listId,oldListId,boardId,comment,user,card,commentId .
       # example: WEBHOOKS_ATTRIBUTES=cardId,listId,oldListId,boardId,comment,user,card,commentId
       # example: WEBHOOKS_ATTRIBUTES=cardId,listId,oldListId,boardId,comment,user,card,commentId
       - WEBHOOKS_ATTRIBUTES=''
       - WEBHOOKS_ATTRIBUTES=''
+      # Enable the OAuth2 connection
+      # example: OAUTH2_ENABLED=true
+      - OAUTH2_ENABLED=false
       # OAuth2 docs: https://github.com/wekan/wekan/wiki/OAuth2
       # OAuth2 docs: https://github.com/wekan/wekan/wiki/OAuth2
       # OAuth2 Client ID, for example from Rocket.Chat. Example: abcde12345
       # OAuth2 Client ID, for example from Rocket.Chat. Example: abcde12345
       # example: OAUTH2_CLIENT_ID=abcde12345
       # example: OAUTH2_CLIENT_ID=abcde12345
@@ -82,6 +85,124 @@ services:
       # OAuth2 Token Endpoint. Example: /oauth/token
       # OAuth2 Token Endpoint. Example: /oauth/token
       # example: OAUTH2_TOKEN_ENDPOINT=/oauth/token
       # example: OAUTH2_TOKEN_ENDPOINT=/oauth/token
       - OAUTH2_TOKEN_ENDPOINT=''
       - OAUTH2_TOKEN_ENDPOINT=''
+      # LDAP_ENABLE : Enable or not the connection by the LDAP
+      # example : LDAP_ENABLE=true
+      - LDAP_ENABLE=false
+      # LDAP_PORT : The port of the LDAP server
+      # example : LDAP_PORT=389
+      - LDAP_PORT=389
+      # LDAP_HOST : The host server for the LDAP server
+      # example : LDAP_HOST=localhost
+      - LDAP_HOST=''
+      # LDAP_BASEDN : The base DN for the LDAP Tree
+      # example : LDAP_BASEDN=ou=user,dc=example,dc=org
+      - LDAP_BASEDN=''
+      # LDAP_LOGIN_FALLBACK : Fallback on the default authentication method
+      # example : LDAP_LOGIN_FALLBACK=true
+      - LDAP_LOGIN_FALLBACK=false
+      # LDAP_RECONNECT : Reconnect to the server if the connection is lost
+      # example : LDAP_RECONNECT=false
+      - LDAP_RECONNECT=true
+      # LDAP_TIMEOUT : Overall timeout, in milliseconds
+      # example : LDAP_TIMEOUT=12345
+      - LDAP_TIMEOUT=10000
+      # LDAP_IDLE_TIMEOUT : Specifies the timeout for idle LDAP connections in milliseconds
+      # example : LDAP_IDLE_TIMEOUT=12345
+      - LDAP_IDLE_TIMEOUT=10000
+      # LDAP_CONNECT_TIMEOUT : Connection timeout, in milliseconds
+      # example : LDAP_CONNECT_TIMEOUT=12345
+      - LDAP_CONNECT_TIMEOUT=10000
+      # LDAP_AUTHENTIFICATION : If the LDAP needs a user account to search
+      # example : LDAP_AUTHENTIFICATION=true
+      - LDAP_AUTHENTIFICATION=false
+      # LDAP_AUTHENTIFICATION_USERDN : The search user DN
+      # example : LDAP_AUTHENTIFICATION_USERDN=cn=admin,dc=example,dc=org
+      - LDAP_AUTHENTIFICATION_USERDN=''
+      # LDAP_AUTHENTIFICATION_PASSWORD : The password for the search user
+      # example : AUTHENTIFICATION_PASSWORD=admin
+      - LDAP_AUTHENTIFICATION_PASSWORD=''
+      # LDAP_LOG_ENABLED : Enable logs for the module
+      # example : LDAP_LOG_ENABLED=true
+      - LDAP_LOG_ENABLED=false
+      # LDAP_BACKGROUND_SYNC : If the sync of the users should be done in the background
+      # example : LDAP_BACKGROUND_SYNC=true
+      - LDAP_BACKGROUND_SYNC=false
+      # LDAP_BACKGROUND_SYNC_INTERVAL : At which interval does the background task sync in milliseconds
+      # example : LDAP_BACKGROUND_SYNC_INTERVAL=12345
+      - LDAP_BACKGROUND_SYNC_INTERVAL=100
+      # LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED : 
+      # example : LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED=true
+      - LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED=false
+      # LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS : 
+      # example : LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS=true
+      - LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS=false
+      # LDAP_ENCRYPTION : If using LDAPS
+      # example : LDAP_ENCRYPTION=true
+      - LDAP_ENCRYPTION=false
+      # LDAP_CA_CERT : The certification for the LDAPS server
+      # example : LDAP_CA_CERT=-----BEGIN CERTIFICATE-----MIIE+zCCA+OgAwIBAgIkAhwR/6TVLmdRY6hHxvUFWc0+Enmu/Hu6cj+G2FIdAgIC...-----END CERTIFICATE-----
+      - LDAP_CA_CERT=''
+      # LDAP_REJECT_UNAUTHORIZED : Reject Unauthorized Certificate
+      # example : LDAP_REJECT_UNAUTHORIZED=true
+      - LDAP_REJECT_UNAUTHORIZED=false
+      # LDAP_USER_SEARCH_FILTER : Optional extra LDAP filters. Don't forget the outmost enclosing parentheses if needed
+      # example : LDAP_USER_SEARCH_FILTER=
+      - LDAP_USER_SEARCH_FILTER=''
+      # LDAP_USER_SEARCH_SCOPE : Base (search only in the provided DN), one (search only in the provided DN and one level deep), or subtree (search the whole subtree)
+      # example : LDAP_USER_SEARCH_SCOPE=one
+      - LDAP_USER_SEARCH_SCOPE=''
+      # LDAP_USER_SEARCH_FIELD : Which field is used to find the user
+      # example : LDAP_USER_SEARCH_FIELD=uid
+      - LDAP_USER_SEARCH_FIELD=''
+      # LDAP_SEARCH_PAGE_SIZE : Used for pagination (0=unlimited)
+      # example : LDAP_SEARCH_PAGE_SIZE=12345
+      - LDAP_SEARCH_PAGE_SIZE=0
+      # LDAP_SEARCH_SIZE_LIMIT : The limit number of entries (0=unlimited)
+      # example : LDAP_SEARCH_SIZE_LIMIT=12345
+      - LDAP_SEARCH_SIZE_LIMIT=0
+      # LDAP_GROUP_FILTER_ENABLE : Enable group filtering
+      # example : LDAP_GROUP_FILTER_ENABLE=true
+      - LDAP_GROUP_FILTER_ENABLE=false
+      # LDAP_GROUP_FILTER_OBJECTCLASS : The object class for filtering
+      # example : LDAP_GROUP_FILTER_OBJECTCLASS=group
+      - LDAP_GROUP_FILTER_OBJECTCLASS=''
+      # LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE : 
+      # example : 
+      - LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE=''
+      # LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE : 
+      # example : 
+      - LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE=''
+      # LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT : 
+      # example : 
+      - LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT=''
+      # LDAP_GROUP_FILTER_GROUP_NAME : 
+      # example : 
+      - LDAP_GROUP_FILTER_GROUP_NAME=''
+      # LDAP_UNIQUE_IDENTIFIER_FIELD : This field is sometimes class GUID (Globally Unique Identifier)
+      # example : LDAP_UNIQUE_IDENTIFIER_FIELD=guid
+      - LDAP_UNIQUE_IDENTIFIER_FIELD=''
+      # LDAP_UTF8_NAMES_SLUGIFY : Convert the username to utf8
+      # example : LDAP_UTF8_NAMES_SLUGIFY=false
+      - LDAP_UTF8_NAMES_SLUGIFY=true
+      # LDAP_USERNAME_FIELD : Which field contains the ldap username
+      # example : LDAP_USERNAME_FIELD=username
+      - LDAP_USERNAME_FIELD=''
+      # LDAP_MERGE_EXISTING_USERS : 
+      # example : LDAP_MERGE_EXISTING_USERS=true
+      - LDAP_MERGE_EXISTING_USERS=false
+      # LDAP_SYNC_USER_DATA : 
+      # example : LDAP_SYNC_USER_DATA=true
+      - LDAP_SYNC_USER_DATA=false
+      # LDAP_SYNC_USER_DATA_FIELDMAP : 
+      # example : LDAP_SYNC_USER_DATA_FIELDMAP={\"cn\":\"name\", \"mail\":\"email\"}
+      - LDAP_SYNC_USER_DATA_FIELDMAP=''
+      # LDAP_SYNC_GROUP_ROLES : 
+      # example : 
+      - LDAP_SYNC_GROUP_ROLES=''
+      # LDAP_DEFAULT_DOMAIN : 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=''
+
     depends_on:
     depends_on:
       - wekandb
       - wekandb
 
 

+ 6 - 1
i18n/en.i18n.json

@@ -607,5 +607,10 @@
     "r-d-check-of-list": "of checklist",
     "r-d-check-of-list": "of checklist",
     "r-d-add-checklist": "Add checklist",
     "r-d-add-checklist": "Add checklist",
     "r-d-remove-checklist": "Remove checklist",
     "r-d-remove-checklist": "Remove checklist",
-    "r-when-a-card-is-moved": "When a card is moved to another list"
+    "r-when-a-card-is-moved": "When a card is moved to another list",
+    "ldap": "Ldap",
+    "oauth2": "Oauth2",
+    "cas": "Cas",
+    "authentication-method": "Authentication method",
+    "authentication-type": "Authentication type"
 }
 }

+ 1 - 1
models/settings.js

@@ -223,7 +223,7 @@ if (Meteor.isServer) {
     },
     },
 
 
     // Gets all connection methods to use it in the Template
     // Gets all connection methods to use it in the Template
-    getConnectionsEnabled() {
+    getAuthenticationsEnabled() {
       return {
       return {
         ldap: isLdapEnabled(),
         ldap: isLdapEnabled(),
         oauth2: isOauth2Enabled(),
         oauth2: isOauth2Enabled(),

+ 8 - 6
models/users.js

@@ -127,10 +127,10 @@ Users.attachSchema(new SimpleSchema({
     type: Boolean,
     type: Boolean,
     optional: true,
     optional: true,
   },
   },
-  // TODO : write a migration and check if using a ldap parameter is better than a connection_type parameter
-  ldap: {
-    type: Boolean,
-    optional: true,
+  'authenticationMethod': {
+    type: String,
+    optional: false,
+    defaultValue: 'password',
   },
   },
 }));
 }));
 
 
@@ -499,6 +499,7 @@ if (Meteor.isServer) {
       user.emails = [{ address: email, verified: true }];
       user.emails = [{ address: email, verified: true }];
       const initials = user.services.oidc.fullname.match(/\b[a-zA-Z]/g).join('').toUpperCase();
       const initials = user.services.oidc.fullname.match(/\b[a-zA-Z]/g).join('').toUpperCase();
       user.profile = { initials, fullname: user.services.oidc.fullname };
       user.profile = { initials, fullname: user.services.oidc.fullname };
+      user['authenticationMethod'] = 'oauth2';
 
 
       // see if any existing user has this email address or username, otherwise create new
       // see if any existing user has this email address or username, otherwise create new
       const existingUser = Meteor.users.findOne({$or: [{'emails.address': email}, {'username':user.username}]});
       const existingUser = Meteor.users.findOne({$or: [{'emails.address': email}, {'username':user.username}]});
@@ -511,6 +512,7 @@ if (Meteor.isServer) {
       existingUser.emails = user.emails;
       existingUser.emails = user.emails;
       existingUser.username = user.username;
       existingUser.username = user.username;
       existingUser.profile = user.profile;
       existingUser.profile = user.profile;
+      existingUser['authenticationMethod'] = user['authenticationMethod'];
 
 
       Meteor.users.remove({_id: existingUser._id}); // remove existing record
       Meteor.users.remove({_id: existingUser._id}); // remove existing record
       return existingUser;
       return existingUser;
@@ -525,7 +527,7 @@ if (Meteor.isServer) {
     // If ldap, bypass the inviation code if the self registration isn't allowed.
     // If ldap, bypass the inviation code if the self registration isn't allowed.
     // TODO : pay attention if ldap field in the user model change to another content ex : ldap field to connection_type
     // TODO : pay attention if ldap field in the user model change to another content ex : ldap field to connection_type
     if (options.ldap || !disableRegistration) {
     if (options.ldap || !disableRegistration) {
-      user.ldap = true;
+      user['authenticationMethod'] = 'ldap';
       return user;
       return user;
     }
     }
 
 
@@ -645,7 +647,7 @@ if (Meteor.isServer) {
     const disableRegistration = Settings.findOne().disableRegistration;
     const disableRegistration = Settings.findOne().disableRegistration;
     // If ldap, bypass the inviation code if the self registration isn't allowed.
     // If ldap, bypass the inviation code if the self registration isn't allowed.
     // TODO : pay attention if ldap field in the user model change to another content ex : ldap field to connection_type
     // TODO : pay attention if ldap field in the user model change to another content ex : ldap field to connection_type
-    if (!doc.ldap && disableRegistration) {
+    if (doc['authenticationMethod'] !== 'ldap' && disableRegistration) {
       const invitationCode = InvitationCodes.findOne({code: doc.profile.icode, valid: true});
       const invitationCode = InvitationCodes.findOne({code: doc.profile.icode, valid: true});
       if (!invitationCode) {
       if (!invitationCode) {
         throw new Meteor.Error('error-invitation-code-not-exist');
         throw new Meteor.Error('error-invitation-code-not-exist');

+ 3 - 1
sandstorm-pkgdef.capnp

@@ -245,12 +245,14 @@ const myCommand :Spk.Manifest.Command = (
     (key = "BROWSER_POLICY_ENABLED", value="true"),
     (key = "BROWSER_POLICY_ENABLED", value="true"),
     (key = "TRUSTED_URL", value=""),
     (key = "TRUSTED_URL", value=""),
     (key = "WEBHOOKS_ATTRIBUTES", value=""),
     (key = "WEBHOOKS_ATTRIBUTES", value=""),
-    (key = "OAUTH2_CLIENT_ID", value=""),
+    (key = "OAUTH2_ENABLED", value=""),
+    (key = "OAUTH2_CLIENT_ID", value="false"),
     (key = "OAUTH2_SECRET", value=""),
     (key = "OAUTH2_SECRET", value=""),
     (key = "OAUTH2_SERVER_URL", value=""),
     (key = "OAUTH2_SERVER_URL", value=""),
     (key = "OAUTH2_AUTH_ENDPOINT", value=""),
     (key = "OAUTH2_AUTH_ENDPOINT", value=""),
     (key = "OAUTH2_USERINFO_ENDPOINT", value=""),
     (key = "OAUTH2_USERINFO_ENDPOINT", value=""),
     (key = "OAUTH2_TOKEN_ENDPOINT", value=""),
     (key = "OAUTH2_TOKEN_ENDPOINT", value=""),
+    (key = "LDAP_ENABLE", value="false"),
     (key = "SANDSTORM", value = "1"),
     (key = "SANDSTORM", value = "1"),
     (key = "METEOR_SETTINGS", value = "{\"public\": {\"sandstorm\": true}}")
     (key = "METEOR_SETTINGS", value = "{\"public\": {\"sandstorm\": true}}")
   ]
   ]

+ 12 - 0
server/migrations.js

@@ -321,3 +321,15 @@ Migrations.add('add-subtasks-allowed', () => {
     },
     },
   }, noValidateMulti);
   }, noValidateMulti);
 });
 });
+
+Migrations.add('add-authenticationMethod', () => {
+  Users.update({
+    'authenticationMethod': {
+      $exists: false,
+    },
+  }, {
+    $set: {
+      'authenticationMethod': 'password',
+    },
+  }, noValidateMulti);
+});

+ 1 - 0
server/publications/people.js

@@ -17,6 +17,7 @@ Meteor.publish('people', function(limit) {
         'emails': 1,
         'emails': 1,
         'createdAt': 1,
         'createdAt': 1,
         'loginDisabled': 1,
         'loginDisabled': 1,
+        'authenticationMethod': 1
       },
       },
     });
     });
   } else {
   } else {

+ 3 - 4
server/publications/users.js

@@ -18,12 +18,11 @@ Meteor.publish('user-admin', function() {
   });
   });
 });
 });
 
 
-Meteor.publish('user-connection-method', function(match) {
+Meteor.publish('user-authenticationMethod', function(match) {
   check(match, String);
   check(match, String);
-
-  return Users.find({$or: [{email: match}, {username: match}]}, {
+  return Users.find({$or: [{_id: match}, {email: match}, {username: match}]}, {
     fields: {
     fields: {
-      ldap: 1,
+      'authenticationMethod': 1,
     },
     },
   });
   });
 });
 });

+ 160 - 1
snap-src/bin/config

@@ -3,7 +3,7 @@
 # All supported keys are defined here together with descriptions and default values
 # All supported keys are defined here together with descriptions and default values
 
 
 # list of supported keys
 # list of supported keys
-keys="MONGODB_BIND_UNIX_SOCKET MONGODB_BIND_IP MONGODB_PORT MAIL_URL MAIL_FROM ROOT_URL PORT DISABLE_MONGODB CADDY_ENABLED CADDY_BIND_PORT WITH_API MATOMO_ADDRESS MATOMO_SITE_ID MATOMO_DO_NOT_TRACK MATOMO_WITH_USERNAME BROWSER_POLICY_ENABLED TRUSTED_URL WEBHOOKS_ATTRIBUTES OAUTH2_CLIENT_ID OAUTH2_SECRET OAUTH2_SERVER_URL OAUTH2_AUTH_ENDPOINT OAUTH2_USERINFO_ENDPOINT OAUTH2_TOKEN_ENDPOINT"
+keys="MONGODB_BIND_UNIX_SOCKET MONGODB_BIND_IP MONGODB_PORT MAIL_URL MAIL_FROM ROOT_URL PORT DISABLE_MONGODB CADDY_ENABLED CADDY_BIND_PORT WITH_API MATOMO_ADDRESS MATOMO_SITE_ID MATOMO_DO_NOT_TRACK MATOMO_WITH_USERNAME BROWSER_POLICY_ENABLED TRUSTED_URL WEBHOOKS_ATTRIBUTES OAUTH2_ENABLED OAUTH2_CLIENT_ID OAUTH2_SECRET OAUTH2_SERVER_URL OAUTH2_AUTH_ENDPOINT OAUTH2_USERINFO_ENDPOINT OAUTH2_TOKEN_ENDPOINT LDAP_ENABLE LDAP_PORT LDAP_HOST LDAP_BASEDN LDAP_LOGIN_FALLBACK LDAP_RECONNECT LDAP_TIMEOUT LDAP_IDLE_TIMEOUT LDAP_CONNECT_TIMEOUT LDAP_AUTHENTIFICATION LDAP_AUTHENTIFICATION_USERDN LDAP_AUTHENTIFICATION_PASSWORD LDAP_LOG_ENABLED LDAP_BACKGROUND_SYNC LDAP_BACKGROUND_SYNC_INTERVAL LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS LDAP_ENCRYPTION LDAP_CA_CERT LDAP_REJECT_UNAUTHORIZED LDAP_USER_SEARCH_FILTER LDAP_USER_SEARCH_SCOPE LDAP_USER_SEARCH_FIELD LDAP_SEARCH_PAGE_SIZE LDAP_SEARCH_SIZE_LIMIT LDAP_GROUP_FILTER_ENABLE 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 LDAP_UTF8_NAMES_SLUGIFY LDAP_USERNAME_FIELD LDAP_MERGE_EXISTING_USERS LDAP_SYNC_USER_DATA LDAP_SYNC_USER_DATA_FIELDMAP LDAP_SYNC_GROUP_ROLES LDAP_DEFAULT_DOMAIN"
 
 
 # default values
 # default values
 DESCRIPTION_MONGODB_BIND_UNIX_SOCKET="mongodb binding unix socket:\n"\
 DESCRIPTION_MONGODB_BIND_UNIX_SOCKET="mongodb binding unix socket:\n"\
@@ -82,6 +82,10 @@ DESCRIPTION_WEBHOOKS_ATTRIBUTES="What to send to Outgoing Webhook, or leave out.
 DEFAULT_WEBHOOKS_ATTRIBUTES=""
 DEFAULT_WEBHOOKS_ATTRIBUTES=""
 KEY_WEBHOOKS_ATTRIBUTES="webhooks-attributes"
 KEY_WEBHOOKS_ATTRIBUTES="webhooks-attributes"
 
 
+DESCRIPTION_OAUTH2_ENABLED="Enable the OAuth2 connection"
+DEFAULT_OAUTH2_ENABLED="false"
+KEY_OAUTH2_ENABLED="oauth2-enabled"
+
 DESCRIPTION_OAUTH2_CLIENT_ID="OAuth2 Client ID, for example from Rocket.Chat. Example: abcde12345"
 DESCRIPTION_OAUTH2_CLIENT_ID="OAuth2 Client ID, for example from Rocket.Chat. Example: abcde12345"
 DEFAULT_OAUTH2_CLIENT_ID=""
 DEFAULT_OAUTH2_CLIENT_ID=""
 KEY_OAUTH2_CLIENT_ID="oauth2-client-id"
 KEY_OAUTH2_CLIENT_ID="oauth2-client-id"
@@ -106,3 +110,158 @@ DESCRIPTION_OAUTH2_TOKEN_ENDPOINT="OAuth2 token endpoint. Example: /oauth/token"
 DEFAULT_OAUTH2_TOKEN_ENDPOINT=""
 DEFAULT_OAUTH2_TOKEN_ENDPOINT=""
 KEY_OAUTH2_TOKEN_ENDPOINT="oauth2-token-endpoint"
 KEY_OAUTH2_TOKEN_ENDPOINT="oauth2-token-endpoint"
 
 
+DESCRIPTION_LDAP_ENABLE="Enable or not the connection by the LDAP"
+DEFAULT_LDAP_ENABLE="false"
+KEY_LDAP_ENABLE="ldap-enable"
+
+DESCRIPTION_LDAP_PORT="The port of the LDAP server"
+DEFAULT_LDAP_PORT="389"
+KEY_LDAP_PORT="ldap-port"
+
+DESCRIPTION_LDAP_HOST="The host server for the LDAP server"
+DEFAULT_LDAP_HOST=""
+KEY_LDAP_HOST="ldap-host"
+
+DESCRIPTION_LDAP_BASEDN="The base DN for the LDAP Tree"
+DEFAULT_LDAP_BASEDN=""
+KEY_LDAP_BASEDN="ldap-basedn"
+
+DESCRIPTION_LDAP_LOGIN_FALLBACK="Fallback on the default authentication method"
+DEFAULT_LDAP_LOGIN_FALLBACK="false"
+KEY_LDAP_LOGIN_FALLBACK="ldap-login-fallback"
+
+DESCRIPTION_LDAP_RECONNECT="Reconnect to the server if the connection is lost"
+DEFAULT_LDAP_RECONNECT="true"
+KEY_LDAP_RECONNECT="ldap-reconnect"
+
+DESCRIPTION_LDAP_TIMEOUT="Overall timeout, in milliseconds."
+DEFAULT_LDAP_TIMEOUT="10000"
+KEY_LDAP_TIMEOUT="ldap-timeout"
+
+DESCRIPTION_LDAP_IDLE_TIMEOUT="Specifies the timeout for idle LDAP connections in milliseconds"
+DEFAULT_LDAP_IDLE_TIMEOUT="10000"
+KEY_LDAP_IDLE_TIMEOUT="ldap-idle-timeout"
+
+DESCRIPTION_LDAP_CONNECT_TIMEOUT="Connection timeout, in milliseconds."
+DEFAULT_LDAP_CONNECT_TIMEOUT="10000"
+KEY_LDAP_CONNECT_TIMEOUT="ldap-connect-timeout"
+
+DESCRIPTION_LDAP_AUTHENTIFICATION="If the LDAP needs a user account to search"
+DEFAULT_LDAP_AUTHENTIFICATION="false"
+KEY_LDAP_AUTHENTIFICATION="ldap-authentication"
+
+DESCRIPTION_LDAP_AUTHENTIFICATION_USERDN="The search user DN"
+DEFAULT_LDAP_AUTHENTIFICATION_USERDN=""
+KEY_LDAP_AUTHENTIFICATION_USERDN="ldap-authentication-userdn"
+
+DESCRIPTION_LDAP_AUTHENTIFICATION_PASSWORD="The password for the search user"
+DEFAULT_LDAP_AUTHENTIFICATION_PASSWORD=""
+KEY_LDAP_AUTHENTIFICATION_PASSWORD="ldap-authentication-password"
+
+DESCRIPTION_LDAP_LOG_ENABLED="Enable logs for the module"
+DEFAULT_LDAP_LOG_ENABLED="false"
+KEY_LDAP_LOG_ENABLED="ldap-log-enabled"
+
+DESCRIPTION_LDAP_BACKGROUND_SYNC="If the sync of the users should be done in the background"
+DEFAULT_LDAP_BACKGROUND_SYNC="false"
+KEY_LDAP_BACKGROUND_SYNC="ldap-background-sync"
+
+DESCRIPTION_LDAP_BACKGROUND_SYNC_INTERVAL="At which interval does the background task sync in milliseconds"
+DEFAULT_LDAP_BACKGROUND_SYNC_INTERVAL="100"
+KEY_LDAP_BACKGROUND_SYNC_INTERVAL="ldap-background-sync-interval"
+
+DESCRIPTION_LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED=""
+DEFAULT_LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED="false"
+KEY_LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED="ldap-background-sync-keep-existant-users-updated"
+
+DESCRIPTION_LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS=""
+DEFAULT_LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS="false"
+KEY_LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS="ldap-background-sync-import-new-users" 
+
+DESCRIPTION_LDAP_ENCRYPTION="If using LDAPS"
+DEFAULT_LDAP_ENCRYPTION="false"
+KEY_LDAP_ENCRYPTION="ldap-encryption"
+
+DESCRIPTION_LDAP_CA_CERT="The certification for the LDAPS server"
+DEFAULT_LDAP_CA_CERT=""
+KEY_LDAP_CA_CERT="ldap-ca-cert"
+
+DESCRIPTION_LDAP_REJECT_UNAUTHORIZED="Reject Unauthorized Certificate"
+DEFAULT_LDAP_REJECT_UNAUTHORIZED="false"
+KEY_LDAP_REJECT_UNAUTHORIZED="ldap-reject-unauthorized"
+
+DESCRIPTION_LDAP_USER_SEARCH_FILTER="Optional extra LDAP filters. Don't forget the outmost enclosing parentheses if needed"
+DEFAULT_LDAP_USER_SEARCH_FILTER=""
+KEY_LDAP_USER_SEARCH_FILTER="ldap-user-search-filter"
+
+DESCRIPTION_LDAP_USER_SEARCH_SCOPE="Base (search only in the provided DN), one (search only in the provided DN and one level deep), or subtree (search the whole subtree)."
+DEFAULT_LDAP_USER_SEARCH_SCOPE=""
+KEY_LDAP_USER_SEARCH_SCOPE="ldap-user-search-scope"
+
+DESCRIPTION_LDAP_USER_SEARCH_FIELD="Which field is used to find the user"
+DEFAULT_LDAP_USER_SEARCH_FIELD=""
+KEY_LDAP_USER_SEARCH_FIELD="ldap-user-search-field"
+
+DESCRIPTION_LDAP_SEARCH_PAGE_SIZE="Used for pagination (0=unlimited)"
+DEFAULT_LDAP_SEARCH_PAGE_SIZE="0"
+KEY_LDAP_SEARCH_PAGE_SIZE="ldap-search-page-size"
+
+DESCRIPTION_LDAP_SEARCH_SIZE_LIMIT="The limit number of entries (0=unlimited)"
+DEFAULT_LDAP_SEARCH_SIZE_LIMIT="0"
+KEY_LDAP_SEARCH_SIZE_LIMIT="ldap-search-size-limit"
+
+DESCRIPTION_LDAP_GROUP_FILTER_ENABLE="Enable group filtering"
+DEFAULT_LDAP_GROUP_FILTER_ENABLE="false"
+KEY_LDAP_GROUP_FILTER_ENABLE="ldap-group-filter-enable"
+
+DESCRIPTION_LDAP_GROUP_FILTER_OBJECTCLASS="The object class for filtering"
+DEFAULT_LDAP_GROUP_FILTER_OBJECTCLASS=""
+KEY_LDAP_GROUP_FILTER_OBJECTCLASS="ldap-group-filter-objectclass"
+
+DESCRIPTION_LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE=""
+DEFAULT_LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE=""
+KEY_LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE="ldap-group-filter-id-attribute"
+
+DESCRIPTION_LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE=""
+DEFAULT_LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE=""
+KEY_LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE="ldap-group-filter-member-attribute"
+
+DESCRIPTION_LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT=""
+DEFAULT_LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT=""
+KEY_LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT="ldap-group-filter-member-format"
+
+DESCRIPTION_LDAP_GROUP_FILTER_GROUP_NAME=""
+DEFAULT_LDAP_GROUP_FILTER_GROUP_NAME=""
+KEY_LDAP_GROUP_FILTER_GROUP_NAME="ldap-group-filter-member-format"
+
+DESCRIPTION_LDAP_UNIQUE_IDENTIFIER_FIELD="This field is sometimes class GUID (Globally Unique Identifier)"
+DEFAULT_LDAP_UNIQUE_IDENTIFIER_FIELD=""
+KEY_LDAP_UNIQUE_IDENTIFIER_FIELD="ldap-unique-identifier-field"
+
+DESCRIPTION_LDAP_UTF8_NAMES_SLUGIFY="Convert the username to utf8"
+DEFAULT_LDAP_UTF8_NAMES_SLUGIFY="true"
+KEY_LDAP_UTF8_NAMES_SLUGIFY="ldap-utf8-names-slugify"
+
+DESCRIPTION_LDAP_USERNAME_FIELD="Which field contains the ldap username"
+DEFAULT_LDAP_USERNAME_FIELD=""
+KEY_LDAP_USERNAME_FIELD="ldap-username-field"
+
+DESCRIPTION_LDAP_MERGE_EXISTING_USERS=""
+DEFAULT_LDAP_MERGE_EXISTING_USERS="false"
+KEY_LDAP_MERGE_EXISTING_USERS="ldap-merge-existing-users"
+
+DESCRIPTION_LDAP_SYNC_USER_DATA=""
+DEFAULT_LDAP_SYNC_USER_DATA="false"
+KEY_LDAP_SYNC_USER_DATA="ldap-sync-user-data"
+
+DESCRIPTION_LDAP_SYNC_USER_DATA_FIELDMAP=""
+DEFAULT_LDAP_SYNC_USER_DATA_FIELDMAP=""
+KEY_LDAP_SYNC_USER_DATA_FIELDMAP="ldap-sync-user-data-fieldmap"
+
+DESCRIPTION_LDAP_SYNC_GROUP_ROLES=""
+DEFAULT_LDAP_SYNC_GROUP_ROLES=""
+KEY_LDAP_SYNC_GROUP_ROLES="ldap-sync-group-roles"
+
+DESCRIPTION_LDAP_DEFAULT_DOMAIN="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"
+DEFAULT_LDAP_DEFAULT_DOMAIN=""
+KEY_LDAP_DEFAULT_DOMAIN="ldap-default-domain"