diff options
-rw-r--r-- | CHANGELOG.md | 15 | ||||
-rw-r--r-- | Dockerfile | 1 | ||||
-rw-r--r-- | Stackerfile.yml | 2 | ||||
-rw-r--r-- | docker-compose.yml | 3 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | packages/wekan-ldap/server/ldap.js | 182 | ||||
-rw-r--r-- | packages/wekan-ldap/server/loginHandler.js | 52 | ||||
-rwxr-xr-x | releases/virtualbox/start-wekan.sh | 2 | ||||
-rw-r--r-- | sandstorm-pkgdef.capnp | 4 | ||||
-rwxr-xr-x | snap-src/bin/config | 6 | ||||
-rwxr-xr-x | snap-src/bin/wekan-help | 3 | ||||
-rwxr-xr-x | start-wekan.bat | 3 | ||||
-rwxr-xr-x | start-wekan.sh | 2 |
13 files changed, 173 insertions, 104 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 28c01948..8e486a89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,22 @@ +# v2.68 2019-05-10 Wekan release + +This release adds the following new features: + +- [Option to login to the LDAP server with the user's own username and password, instead of an administrator + key](https://github.com/wekan/wekan/pull/2399). Default: false (use administrator key). + With new setting: LDAP_USER_AUTHENTICATION=true. + Thanks to thiagofernando. +- [Added above new LDAP_USER_AUTHENTION=true option to Snap, Docker and Source settings](https://github.com/wekan/wekan/commit/3bbc805ee42e3c1638b50260d3fafc2b5f936923). + Thanks to xet7. + +Thanks to above GitHub users for their contributions and translators for their translations. + # v2.67 2019-05-10 Wekan release This release adds the following new features: - [Move board to Archive button at each board at All Boards page](https://github.com/wekan/wekan/commit/828f6ea321020eda77fea399df52889e2081dfac). - Thanks to xet7. Related #2389 + Thanks to xet7. Related [#2389](https://github.com/wekan/wekan/issues/2389). - [If adding Subtasks does not work on old board, added wiki page how to make it work again](https://github.com/wekan/wekan/wiki/Subtasks). Thanks to xet7. @@ -61,6 +61,7 @@ ENV BUILD_DEPS="apt-utils bsdtar gnupg gosu wget curl bzip2 build-essential pyth LDAP_ENCRYPTION=false \ LDAP_CA_CERT="" \ LDAP_REJECT_UNAUTHORIZED=false \ + LDAP_USER_AUTHENTICATION=false \ LDAP_USER_SEARCH_FILTER="" \ LDAP_USER_SEARCH_SCOPE="" \ LDAP_USER_SEARCH_FIELD="" \ diff --git a/Stackerfile.yml b/Stackerfile.yml index 2302fa1c..9ef9b981 100644 --- a/Stackerfile.yml +++ b/Stackerfile.yml @@ -1,5 +1,5 @@ appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928 -appVersion: "v2.67.0" +appVersion: "v2.68.0" files: userUploads: - README.md diff --git a/docker-compose.yml b/docker-compose.yml index 5dca833d..68cb363a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -400,6 +400,9 @@ services: # 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" + # # Optional extra LDAP filters. Don't forget the outmost enclosing parentheses if needed #- LDAP_USER_SEARCH_FILTER= # diff --git a/package.json b/package.json index e6a55087..e117e075 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wekan", - "version": "v2.67.0", + "version": "v2.68.0", "description": "Open-Source kanban", "private": true, "scripts": { diff --git a/packages/wekan-ldap/server/ldap.js b/packages/wekan-ldap/server/ldap.js index 555a30aa..56429dce 100644 --- a/packages/wekan-ldap/server/ldap.js +++ b/packages/wekan-ldap/server/ldap.js @@ -1,41 +1,44 @@ import ldapjs from 'ldapjs'; import util from 'util'; import Bunyan from 'bunyan'; -import { log_debug, log_info, log_warn, log_error } from './logger'; +import {log_debug, log_info, log_warn, log_error} from './logger'; + export default class LDAP { - constructor(){ + constructor() { this.ldapjs = ldapjs; this.connected = false; this.options = { - host: this.constructor.settings_get('LDAP_HOST'), - port: this.constructor.settings_get('LDAP_PORT'), - Reconnect: this.constructor.settings_get('LDAP_RECONNECT'), - timeout: this.constructor.settings_get('LDAP_TIMEOUT'), - connect_timeout: this.constructor.settings_get('LDAP_CONNECT_TIMEOUT'), - idle_timeout: this.constructor.settings_get('LDAP_IDLE_TIMEOUT'), - encryption: this.constructor.settings_get('LDAP_ENCRYPTION'), - ca_cert: this.constructor.settings_get('LDAP_CA_CERT'), - reject_unauthorized: this.constructor.settings_get('LDAP_REJECT_UNAUTHORIZED') || false, - Authentication: this.constructor.settings_get('LDAP_AUTHENTIFICATION'), - Authentication_UserDN: this.constructor.settings_get('LDAP_AUTHENTIFICATION_USERDN'), - Authentication_Password: this.constructor.settings_get('LDAP_AUTHENTIFICATION_PASSWORD'), - Authentication_Fallback: this.constructor.settings_get('LDAP_LOGIN_FALLBACK'), - BaseDN: this.constructor.settings_get('LDAP_BASEDN'), - Internal_Log_Level: this.constructor.settings_get('INTERNAL_LOG_LEVEL'), - User_Search_Filter: this.constructor.settings_get('LDAP_USER_SEARCH_FILTER'), - User_Search_Scope: this.constructor.settings_get('LDAP_USER_SEARCH_SCOPE'), - User_Search_Field: this.constructor.settings_get('LDAP_USER_SEARCH_FIELD'), - Search_Page_Size: this.constructor.settings_get('LDAP_SEARCH_PAGE_SIZE'), - Search_Size_Limit: this.constructor.settings_get('LDAP_SEARCH_SIZE_LIMIT'), - group_filter_enabled: this.constructor.settings_get('LDAP_GROUP_FILTER_ENABLE'), - group_filter_object_class: this.constructor.settings_get('LDAP_GROUP_FILTER_OBJECTCLASS'), - group_filter_group_id_attribute: this.constructor.settings_get('LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE'), + host : this.constructor.settings_get('LDAP_HOST'), + port : this.constructor.settings_get('LDAP_PORT'), + Reconnect : this.constructor.settings_get('LDAP_RECONNECT'), + timeout : this.constructor.settings_get('LDAP_TIMEOUT'), + connect_timeout : this.constructor.settings_get('LDAP_CONNECT_TIMEOUT'), + idle_timeout : this.constructor.settings_get('LDAP_IDLE_TIMEOUT'), + encryption : this.constructor.settings_get('LDAP_ENCRYPTION'), + ca_cert : this.constructor.settings_get('LDAP_CA_CERT'), + reject_unauthorized : this.constructor.settings_get('LDAP_REJECT_UNAUTHORIZED') || false, + Authentication : this.constructor.settings_get('LDAP_AUTHENTIFICATION'), + Authentication_UserDN : this.constructor.settings_get('LDAP_AUTHENTIFICATION_USERDN'), + Authentication_Password : this.constructor.settings_get('LDAP_AUTHENTIFICATION_PASSWORD'), + Authentication_Fallback : this.constructor.settings_get('LDAP_LOGIN_FALLBACK'), + BaseDN : this.constructor.settings_get('LDAP_BASEDN'), + Internal_Log_Level : this.constructor.settings_get('INTERNAL_LOG_LEVEL'), + User_Authentication : this.constructor.settings_get('LDAP_USER_AUTHENTICATION'), + User_Attributes : this.constructor.settings_get('LDAP_USER_ATTRIBUTES'), + User_Search_Filter : this.constructor.settings_get('LDAP_USER_SEARCH_FILTER'), + User_Search_Scope : this.constructor.settings_get('LDAP_USER_SEARCH_SCOPE'), + User_Search_Field : this.constructor.settings_get('LDAP_USER_SEARCH_FIELD'), + Search_Page_Size : this.constructor.settings_get('LDAP_SEARCH_PAGE_SIZE'), + Search_Size_Limit : this.constructor.settings_get('LDAP_SEARCH_SIZE_LIMIT'), + group_filter_enabled : this.constructor.settings_get('LDAP_GROUP_FILTER_ENABLE'), + group_filter_object_class : this.constructor.settings_get('LDAP_GROUP_FILTER_OBJECTCLASS'), + group_filter_group_id_attribute : this.constructor.settings_get('LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE'), group_filter_group_member_attribute: this.constructor.settings_get('LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE'), - group_filter_group_member_format: this.constructor.settings_get('LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT'), - group_filter_group_name: this.constructor.settings_get('LDAP_GROUP_FILTER_GROUP_NAME'), + group_filter_group_member_format : this.constructor.settings_get('LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT'), + group_filter_group_name : this.constructor.settings_get('LDAP_GROUP_FILTER_GROUP_NAME'), }; } @@ -52,14 +55,16 @@ export default class LDAP { log_warn(`Lookup for unset variable: ${name}`); } } + connectSync(...args) { - if (!this._connectSync) { + if (!this._connectSync) { this._connectSync = Meteor.wrapAsync(this.connectAsync, this); } return this._connectSync(...args); } searchAllSync(...args) { + if (!this._searchAllSync) { this._searchAllSync = Meteor.wrapAsync(this.searchAllAsync, this); } @@ -72,19 +77,19 @@ export default class LDAP { let replied = false; const connectionOptions = { - url: `${ this.options.host }:${ this.options.port }`, - timeout: this.options.timeout, + url : `${this.options.host}:${this.options.port}`, + timeout : this.options.timeout, connectTimeout: this.options.connect_timeout, - idleTimeout: this.options.idle_timeout, - reconnect: this.options.Reconnect, + idleTimeout : this.options.idle_timeout, + reconnect : this.options.Reconnect, }; if (this.options.Internal_Log_Level !== 'disabled') { connectionOptions.log = new Bunyan({ - name: 'ldapjs', + name : 'ldapjs', component: 'client', - stream: process.stderr, - level: this.options.Internal_Log_Level, + stream : process.stderr, + level : this.options.Internal_Log_Level, }); } @@ -95,8 +100,8 @@ export default class LDAP { if (this.options.ca_cert && this.options.ca_cert !== '') { // Split CA cert into array of strings const chainLines = this.constructor.settings_get('LDAP_CA_CERT').split('\n'); - let cert = []; - const ca = []; + let cert = []; + const ca = []; chainLines.forEach((line) => { cert.push(line); if (line.match(/-END CERTIFICATE-/)) { @@ -108,14 +113,14 @@ export default class LDAP { } if (this.options.encryption === 'ssl') { - connectionOptions.url = `ldaps://${ connectionOptions.url }`; + connectionOptions.url = `ldaps://${connectionOptions.url}`; connectionOptions.tlsOptions = tlsOptions; } else { - connectionOptions.url = `ldap://${ connectionOptions.url }`; + connectionOptions.url = `ldap://${connectionOptions.url}`; } log_info('Connecting', connectionOptions.url); - log_debug(`connectionOptions${ util.inspect(connectionOptions)}`); + log_debug(`connectionOptions${util.inspect(connectionOptions)}`); this.client = ldapjs.createClient(connectionOptions); @@ -189,23 +194,42 @@ export default class LDAP { if (this.options.User_Search_Filter !== '') { if (this.options.User_Search_Filter[0] === '(') { - filter.push(`${ this.options.User_Search_Filter }`); + filter.push(`${this.options.User_Search_Filter}`); } else { - filter.push(`(${ this.options.User_Search_Filter })`); + filter.push(`(${this.options.User_Search_Filter})`); } } - const usernameFilter = this.options.User_Search_Field.split(',').map((item) => `(${ item }=${ username })`); + const usernameFilter = this.options.User_Search_Field.split(',').map((item) => `(${item}=${username})`); if (usernameFilter.length === 0) { log_error('LDAP_LDAP_User_Search_Field not defined'); } else if (usernameFilter.length === 1) { - filter.push(`${ usernameFilter[0] }`); + filter.push(`${usernameFilter[0]}`); } else { - filter.push(`(|${ usernameFilter.join('') })`); + filter.push(`(|${usernameFilter.join('')})`); + } + + return `(&${filter.join('')})`; + } + + bindUserIfNecessary(username, password) { + + if (this.domainBinded === true) { + return; + } + + if (!this.options.User_Authentication) { + return; } - return `(&${ filter.join('') })`; + + if (!this.options.BaseDN) throw new Error('BaseDN is not provided'); + + const userDn = `uid=${username},${this.options.BaseDN}`; + + this.bindSync(userDn, password); + this.domainBinded = true; } bindIfNecessary() { @@ -218,22 +242,24 @@ export default class LDAP { } log_info('Binding UserDN', this.options.Authentication_UserDN); + this.bindSync(this.options.Authentication_UserDN, this.options.Authentication_Password); this.domainBinded = true; } searchUsersSync(username, page) { this.bindIfNecessary(); - const searchOptions = { - filter: this.getUserFilter(username), - scope: this.options.User_Search_Scope || 'sub', + filter : this.getUserFilter(username), + scope : this.options.User_Search_Scope || 'sub', sizeLimit: this.options.Search_Size_Limit, }; + if (!!this.options.User_Attributes) searchOptions.attributes = this.options.User_Attributes.split(','); + if (this.options.Search_Page_Size > 0) { searchOptions.paged = { - pageSize: this.options.Search_Page_Size, + pageSize : this.options.Search_Page_Size, pagePause: !!page, }; } @@ -266,11 +292,11 @@ export default class LDAP { Unique_Identifier_Field.forEach((item) => { filters.push(new this.ldapjs.filters.EqualityFilter({ attribute: item, - value: new Buffer(id, 'hex'), + value : new Buffer(id, 'hex'), })); }); - filter = new this.ldapjs.filters.OrFilter({filters}); + filter = new this.ldapjs.filters.OrFilter({ filters }); } const searchOptions = { @@ -300,7 +326,7 @@ export default class LDAP { const searchOptions = { filter: this.getUserFilter(username), - scope: this.options.User_Search_Scope || 'sub', + scope : this.options.User_Search_Scope || 'sub', }; log_info('Searching user', username); @@ -320,7 +346,7 @@ export default class LDAP { return result[0]; } - getUserGroups(username, ldapUser){ + getUserGroups(username, ldapUser) { if (!this.options.group_filter_enabled) { return true; } @@ -328,13 +354,13 @@ export default class LDAP { const filter = ['(&']; if (this.options.group_filter_object_class !== '') { - filter.push(`(objectclass=${ this.options.group_filter_object_class })`); + filter.push(`(objectclass=${this.options.group_filter_object_class})`); } if (this.options.group_filter_group_member_attribute !== '') { const format_value = ldapUser[this.options.group_filter_group_member_format]; - if( format_value ) { - filter.push(`(${ this.options.group_filter_group_member_attribute }=${ format_value })`); + if (format_value) { + filter.push(`(${this.options.group_filter_group_member_attribute}=${format_value})`); } } @@ -342,7 +368,7 @@ export default class LDAP { const searchOptions = { filter: filter.join('').replace(/#{username}/g, username), - scope: 'sub', + scope : 'sub', }; log_debug('Group list filter LDAP:', searchOptions.filter); @@ -354,11 +380,11 @@ export default class LDAP { } const grp_identifier = this.options.group_filter_group_id_attribute || 'cn'; - const groups = []; + const groups = []; result.map((item) => { - groups.push( item[ grp_identifier ] ); + groups.push(item[grp_identifier]); }); - log_debug(`Groups: ${ groups.join(', ')}`); + log_debug(`Groups: ${groups.join(', ')}`); return groups; } @@ -373,24 +399,24 @@ export default class LDAP { const filter = ['(&']; if (this.options.group_filter_object_class !== '') { - filter.push(`(objectclass=${ this.options.group_filter_object_class })`); + filter.push(`(objectclass=${this.options.group_filter_object_class})`); } if (this.options.group_filter_group_member_attribute !== '') { const format_value = ldapUser[this.options.group_filter_group_member_format]; - if( format_value ) { - filter.push(`(${ this.options.group_filter_group_member_attribute }=${ format_value })`); + if (format_value) { + filter.push(`(${this.options.group_filter_group_member_attribute}=${format_value})`); } } if (this.options.group_filter_group_id_attribute !== '') { - filter.push(`(${ this.options.group_filter_group_id_attribute }=${ this.options.group_filter_group_name })`); + filter.push(`(${this.options.group_filter_group_id_attribute}=${this.options.group_filter_group_name})`); } filter.push(')'); const searchOptions = { filter: filter.join('').replace(/#{username}/g, username), - scope: 'sub', + scope : 'sub', }; log_debug('Group filter LDAP:', searchOptions.filter); @@ -426,15 +452,17 @@ export default class LDAP { searchAllPaged(BaseDN, options, page) { this.bindIfNecessary(); - const processPage = ({entries, title, end, next}) => { + const processPage = ({ entries, title, end, next }) => { log_info(title); // Force LDAP idle to wait the record processing this.client._updateIdle(true); - page(null, entries, {end, next: () => { - // Reset idle timer - this.client._updateIdle(); - next && next(); - }}); + page(null, entries, { + end, next: () => { + // Reset idle timer + this.client._updateIdle(); + next && next(); + } + }); }; this.client.search(BaseDN, options, (error, res) => { @@ -461,7 +489,7 @@ export default class LDAP { processPage({ entries, title: 'Internal Page', - end: false, + end : false, }); entries = []; } @@ -473,14 +501,14 @@ export default class LDAP { processPage({ entries, title: 'Final Page', - end: true, + end : true, }); } else if (entries.length) { log_info('Page'); processPage({ entries, title: 'Page', - end: false, + end : false, next, }); entries = []; @@ -492,7 +520,7 @@ export default class LDAP { processPage({ entries, title: 'Final Page', - end: true, + end : true, }); entries = []; } @@ -547,7 +575,7 @@ export default class LDAP { } disconnect() { - this.connected = false; + this.connected = false; this.domainBinded = false; log_info('Disconecting'); this.client.unbind(); diff --git a/packages/wekan-ldap/server/loginHandler.js b/packages/wekan-ldap/server/loginHandler.js index a8f013d7..0c1aa33f 100644 --- a/packages/wekan-ldap/server/loginHandler.js +++ b/packages/wekan-ldap/server/loginHandler.js @@ -41,28 +41,38 @@ Accounts.registerLoginHandler('ldap', function(loginRequest) { let ldapUser; try { - ldap.connectSync(); - const users = ldap.searchUsersSync(loginRequest.username); - if (users.length !== 1) { - log_info('Search returned', users.length, 'record(s) for', loginRequest.username); - throw new Error('User not Found'); - } + ldap.connectSync(); + + if (!!LDAP.settings_get('LDAP_USER_AUTHENTICATION')) { + ldap.bindUserIfNecessary(loginRequest.username, loginRequest.ldapPass); + ldapUser = ldap.searchUsersSync(loginRequest.username)[0]; + } else { + + const users = ldap.searchUsersSync(loginRequest.username); + + if (users.length !== 1) { + log_info('Search returned', users.length, 'record(s) for', loginRequest.username); + throw new Error('User not Found'); + } + + if (ldap.authSync(users[0].dn, loginRequest.ldapPass) === true) { + if (ldap.isUserInGroup(loginRequest.username, users[0])) { + ldapUser = users[0]; + } else { + throw new Error('User not in a valid group'); + } + } else { + log_info('Wrong password for', loginRequest.username); + } + } + - if (ldap.authSync(users[0].dn, loginRequest.ldapPass) === true) { - if (ldap.isUserInGroup(loginRequest.username, users[0])) { - ldapUser = users[0]; - } else { - throw new Error('User not in a valid group'); - } - } else { - log_info('Wrong password for', loginRequest.username); - } } catch (error) { - log_error(error); + log_error(error); } - if (ldapUser === undefined) { + if (!ldapUser) { if (LDAP.settings_get('LDAP_LOGIN_FALLBACK') === true) { return fallbackDefaultAccountSystem(self, loginRequest.username, loginRequest.ldapPass); } @@ -76,8 +86,7 @@ Accounts.registerLoginHandler('ldap', function(loginRequest) { const Unique_Identifier_Field = getLdapUserUniqueID(ldapUser); let user; - - // Attempt to find user by unique identifier + // Attempt to find user by unique identifier if (Unique_Identifier_Field) { userQuery = { @@ -88,14 +97,14 @@ Accounts.registerLoginHandler('ldap', function(loginRequest) { log_debug('userQuery', userQuery); user = Meteor.users.findOne(userQuery); - } + } // Attempt to find user by username let username; let email; - if (LDAP.settings_get('LDAP_USERNAME_FIELD') !== '') { + if (LDAP.settings_get('LDAP_USERNAME_FIELD') !== '') { username = slug(getLdapUsername(ldapUser)); } else { username = slug(loginRequest.username); @@ -105,6 +114,7 @@ Accounts.registerLoginHandler('ldap', function(loginRequest) { email = getLdapEmail(ldapUser); } + if (!user) { if(email && LDAP.settings_get('LDAP_EMAIL_MATCH_REQUIRE') === true) { if(LDAP.settings_get('LDAP_EMAIL_MATCH_VERIFIED') === true) { diff --git a/releases/virtualbox/start-wekan.sh b/releases/virtualbox/start-wekan.sh index 14a86dc3..0a44946a 100755 --- a/releases/virtualbox/start-wekan.sh +++ b/releases/virtualbox/start-wekan.sh @@ -191,6 +191,8 @@ # LDAP_REJECT_UNAUTHORIZED : Reject Unauthorized Certificate # example : export LDAP_REJECT_UNAUTHORIZED=true #export 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). + #export LDAP_USER_AUTHENTICATION=true # LDAP_USER_SEARCH_FILTER : Optional extra LDAP filters. Don't forget the outmost enclosing parentheses if needed # example : export LDAP_USER_SEARCH_FILTER= #export LDAP_USER_SEARCH_FILTER= diff --git a/sandstorm-pkgdef.capnp b/sandstorm-pkgdef.capnp index 2dfe5591..d90312a0 100644 --- a/sandstorm-pkgdef.capnp +++ b/sandstorm-pkgdef.capnp @@ -22,10 +22,10 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Wekan"), # The name of the app as it is displayed to the user. - appVersion = 269, + appVersion = 270, # Increment this for every release. - appMarketingVersion = (defaultText = "2.67.0~2019-05-10"), + appMarketingVersion = (defaultText = "2.68.0~2019-05-10"), # Human-readable presentation of the app version. minUpgradableAppVersion = 0, diff --git a/snap-src/bin/config b/snap-src/bin/config index e09cfc19..1d766257 100755 --- a/snap-src/bin/config +++ b/snap-src/bin/config @@ -3,7 +3,7 @@ # All supported keys are defined here together with descriptions and default values # list of supported keys -keys="DEBUG 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 ACCOUNTS_LOCKOUT_KNOWN_USERS_FAILURES_BEFORE ACCOUNTS_LOCKOUT_KNOWN_USERS_PERIOD ACCOUNTS_LOCKOUT_KNOWN_USERS_FAILURE_WINDOW ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURES_BERORE ACCOUNTS_LOCKOUT_UNKNOWN_USERS_LOCKOUT_PERIOD ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW EMAIL_NOTIFICATION_TIMEOUT CORS MATOMO_ADDRESS MATOMO_SITE_ID MATOMO_DO_NOT_TRACK MATOMO_WITH_USERNAME BROWSER_POLICY_ENABLED TRUSTED_URL WEBHOOKS_ATTRIBUTES OAUTH2_ENABLED OAUTH2_LOGIN_STYLE OAUTH2_CLIENT_ID OAUTH2_SECRET OAUTH2_SERVER_URL OAUTH2_AUTH_ENDPOINT OAUTH2_USERINFO_ENDPOINT OAUTH2_TOKEN_ENDPOINT OAUTH2_ID_MAP OAUTH2_USERNAME_MAP OAUTH2_FULLNAME_MAP OAUTH2_EMAIL_MAP 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_FULLNAME_FIELD LDAP_MERGE_EXISTING_USERS LDAP_SYNC_USER_DATA LDAP_SYNC_USER_DATA_FIELDMAP LDAP_SYNC_GROUP_ROLES LDAP_DEFAULT_DOMAIN LDAP_EMAIL_MATCH_ENABLE LDAP_EMAIL_MATCH_REQUIRE LDAP_EMAIL_MATCH_VERIFIED LDAP_EMAIL_FIELD LDAP_SYNC_ADMIN_STATUS LDAP_SYNC_ADMIN_GROUPS HEADER_LOGIN_ID HEADER_LOGIN_FIRSTNAME HEADER_LOGIN_LASTNAME HEADER_LOGIN_EMAIL LOGOUT_WITH_TIMER LOGOUT_IN LOGOUT_ON_HOURS LOGOUT_ON_MINUTES DEFAULT_AUTHENTICATION_METHOD" +keys="DEBUG 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 ACCOUNTS_LOCKOUT_KNOWN_USERS_FAILURES_BEFORE ACCOUNTS_LOCKOUT_KNOWN_USERS_PERIOD ACCOUNTS_LOCKOUT_KNOWN_USERS_FAILURE_WINDOW ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURES_BERORE ACCOUNTS_LOCKOUT_UNKNOWN_USERS_LOCKOUT_PERIOD ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW EMAIL_NOTIFICATION_TIMEOUT CORS MATOMO_ADDRESS MATOMO_SITE_ID MATOMO_DO_NOT_TRACK MATOMO_WITH_USERNAME BROWSER_POLICY_ENABLED TRUSTED_URL WEBHOOKS_ATTRIBUTES OAUTH2_ENABLED OAUTH2_LOGIN_STYLE OAUTH2_CLIENT_ID OAUTH2_SECRET OAUTH2_SERVER_URL OAUTH2_AUTH_ENDPOINT OAUTH2_USERINFO_ENDPOINT OAUTH2_TOKEN_ENDPOINT OAUTH2_ID_MAP OAUTH2_USERNAME_MAP OAUTH2_FULLNAME_MAP OAUTH2_EMAIL_MAP 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_AUTHENTICATION 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_FULLNAME_FIELD LDAP_MERGE_EXISTING_USERS LDAP_SYNC_USER_DATA LDAP_SYNC_USER_DATA_FIELDMAP LDAP_SYNC_GROUP_ROLES LDAP_DEFAULT_DOMAIN LDAP_EMAIL_MATCH_ENABLE LDAP_EMAIL_MATCH_REQUIRE LDAP_EMAIL_MATCH_VERIFIED LDAP_EMAIL_FIELD LDAP_SYNC_ADMIN_STATUS LDAP_SYNC_ADMIN_GROUPS HEADER_LOGIN_ID HEADER_LOGIN_FIRSTNAME HEADER_LOGIN_LASTNAME HEADER_LOGIN_EMAIL LOGOUT_WITH_TIMER LOGOUT_IN LOGOUT_ON_HOURS LOGOUT_ON_MINUTES DEFAULT_AUTHENTICATION_METHOD" # default values DESCRIPTION_DEBUG="Debug OIDC OAuth2 etc. Example: sudo snap set wekan debug='true'" @@ -250,6 +250,10 @@ DESCRIPTION_LDAP_REJECT_UNAUTHORIZED="Reject Unauthorized Certificate" DEFAULT_LDAP_REJECT_UNAUTHORIZED="false" KEY_LDAP_REJECT_UNAUTHORIZED="ldap-reject-unauthorized" +DESCRIPTION_LDAP_USER_AUTHENTICATION="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)." +DEFAULT_LDAP_USER_AUTHENTICATION="false" +KEY_LDAP_USER_AUTHENTICATION="ldap-user-authentication" + 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" diff --git a/snap-src/bin/wekan-help b/snap-src/bin/wekan-help index 64d41d17..59917395 100755 --- a/snap-src/bin/wekan-help +++ b/snap-src/bin/wekan-help @@ -234,6 +234,9 @@ echo -e "Ldap Reject Unauthorized." echo -e "Reject Unauthorized Certificate:" echo -e "\t$ snap set $SNAP_NAME ldap-reject-unauthorized='true'" echo -e "\n" +echo -e "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)." +echo -e "\t$ snap set $SNAP_NAME ldap-user-authentication='true'" +echo -e "\n" echo -e "Ldap User Search Filter." echo -e "Optional extra LDAP filters. Don't forget the outmost enclosing parentheses if needed:" echo -e "\t$ snap set $SNAP_NAME ldap-user-search-filter=''" diff --git a/start-wekan.bat b/start-wekan.bat index d94605bb..7b204f13 100755 --- a/start-wekan.bat +++ b/start-wekan.bat @@ -173,6 +173,9 @@ REM # LDAP_REJECT_UNAUTHORIZED : Reject Unauthorized Certificate REM # example : LDAP_REJECT_UNAUTHORIZED=true REM SET LDAP_REJECT_UNAUTHORIZED=false +REM # 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). +REM SET LDAP_USER_AUTHENTICATION=true + REM # LDAP_USER_SEARCH_FILTER : Optional extra LDAP filters. Don't forget the outmost enclosing parentheses if needed REM # example : LDAP_USER_SEARCH_FILTER= REM SET LDAP_USER_SEARCH_FILTER= diff --git a/start-wekan.sh b/start-wekan.sh index 21a9d4c2..fcf10a36 100755 --- a/start-wekan.sh +++ b/start-wekan.sh @@ -193,6 +193,8 @@ # LDAP_REJECT_UNAUTHORIZED : Reject Unauthorized Certificate # example : export LDAP_REJECT_UNAUTHORIZED=true #export 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). + #export LDAP_USER_AUTHENTICATION=true # LDAP_USER_SEARCH_FILTER : Optional extra LDAP filters. Don't forget the outmost enclosing parentheses if needed # example : export LDAP_USER_SEARCH_FILTER= #export LDAP_USER_SEARCH_FILTER= |