mirror of
https://github.com/wekan/wekan.git
synced 2025-12-18 00:10:13 +01:00
Update ldap.js
This commit is contained in:
parent
ce0473480b
commit
fd1af07e43
1 changed files with 105 additions and 77 deletions
|
|
@ -1,41 +1,44 @@
|
||||||
import ldapjs from 'ldapjs';
|
import ldapjs from 'ldapjs';
|
||||||
import util from 'util';
|
import util from 'util';
|
||||||
import Bunyan from 'bunyan';
|
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 {
|
export default class LDAP {
|
||||||
constructor(){
|
constructor() {
|
||||||
this.ldapjs = ldapjs;
|
this.ldapjs = ldapjs;
|
||||||
|
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
|
|
||||||
this.options = {
|
this.options = {
|
||||||
host: this.constructor.settings_get('LDAP_HOST'),
|
host : this.constructor.settings_get('LDAP_HOST'),
|
||||||
port: this.constructor.settings_get('LDAP_PORT'),
|
port : this.constructor.settings_get('LDAP_PORT'),
|
||||||
Reconnect: this.constructor.settings_get('LDAP_RECONNECT'),
|
Reconnect : this.constructor.settings_get('LDAP_RECONNECT'),
|
||||||
timeout: this.constructor.settings_get('LDAP_TIMEOUT'),
|
timeout : this.constructor.settings_get('LDAP_TIMEOUT'),
|
||||||
connect_timeout: this.constructor.settings_get('LDAP_CONNECT_TIMEOUT'),
|
connect_timeout : this.constructor.settings_get('LDAP_CONNECT_TIMEOUT'),
|
||||||
idle_timeout: this.constructor.settings_get('LDAP_IDLE_TIMEOUT'),
|
idle_timeout : this.constructor.settings_get('LDAP_IDLE_TIMEOUT'),
|
||||||
encryption: this.constructor.settings_get('LDAP_ENCRYPTION'),
|
encryption : this.constructor.settings_get('LDAP_ENCRYPTION'),
|
||||||
ca_cert: this.constructor.settings_get('LDAP_CA_CERT'),
|
ca_cert : this.constructor.settings_get('LDAP_CA_CERT'),
|
||||||
reject_unauthorized: this.constructor.settings_get('LDAP_REJECT_UNAUTHORIZED') || false,
|
reject_unauthorized : this.constructor.settings_get('LDAP_REJECT_UNAUTHORIZED') || false,
|
||||||
Authentication: this.constructor.settings_get('LDAP_AUTHENTIFICATION'),
|
Authentication : this.constructor.settings_get('LDAP_AUTHENTIFICATION'),
|
||||||
Authentication_UserDN: this.constructor.settings_get('LDAP_AUTHENTIFICATION_USERDN'),
|
Authentication_UserDN : this.constructor.settings_get('LDAP_AUTHENTIFICATION_USERDN'),
|
||||||
Authentication_Password: this.constructor.settings_get('LDAP_AUTHENTIFICATION_PASSWORD'),
|
Authentication_Password : this.constructor.settings_get('LDAP_AUTHENTIFICATION_PASSWORD'),
|
||||||
Authentication_Fallback: this.constructor.settings_get('LDAP_LOGIN_FALLBACK'),
|
Authentication_Fallback : this.constructor.settings_get('LDAP_LOGIN_FALLBACK'),
|
||||||
BaseDN: this.constructor.settings_get('LDAP_BASEDN'),
|
BaseDN : this.constructor.settings_get('LDAP_BASEDN'),
|
||||||
Internal_Log_Level: this.constructor.settings_get('INTERNAL_LOG_LEVEL'),
|
Internal_Log_Level : this.constructor.settings_get('INTERNAL_LOG_LEVEL'),
|
||||||
User_Search_Filter: this.constructor.settings_get('LDAP_USER_SEARCH_FILTER'),
|
User_Authentication : this.constructor.settings_get('LDAP_USER_AUTHENTICATION'),
|
||||||
User_Search_Scope: this.constructor.settings_get('LDAP_USER_SEARCH_SCOPE'),
|
User_Attributes : this.constructor.settings_get('LDAP_USER_ATTRIBUTES'),
|
||||||
User_Search_Field: this.constructor.settings_get('LDAP_USER_SEARCH_FIELD'),
|
User_Search_Filter : this.constructor.settings_get('LDAP_USER_SEARCH_FILTER'),
|
||||||
Search_Page_Size: this.constructor.settings_get('LDAP_SEARCH_PAGE_SIZE'),
|
User_Search_Scope : this.constructor.settings_get('LDAP_USER_SEARCH_SCOPE'),
|
||||||
Search_Size_Limit: this.constructor.settings_get('LDAP_SEARCH_SIZE_LIMIT'),
|
User_Search_Field : this.constructor.settings_get('LDAP_USER_SEARCH_FIELD'),
|
||||||
group_filter_enabled: this.constructor.settings_get('LDAP_GROUP_FILTER_ENABLE'),
|
Search_Page_Size : this.constructor.settings_get('LDAP_SEARCH_PAGE_SIZE'),
|
||||||
group_filter_object_class: this.constructor.settings_get('LDAP_GROUP_FILTER_OBJECTCLASS'),
|
Search_Size_Limit : this.constructor.settings_get('LDAP_SEARCH_SIZE_LIMIT'),
|
||||||
group_filter_group_id_attribute: this.constructor.settings_get('LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE'),
|
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_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_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_name : this.constructor.settings_get('LDAP_GROUP_FILTER_GROUP_NAME'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,6 +55,7 @@ export default class LDAP {
|
||||||
log_warn(`Lookup for unset variable: ${name}`);
|
log_warn(`Lookup for unset variable: ${name}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connectSync(...args) {
|
connectSync(...args) {
|
||||||
if (!this._connectSync) {
|
if (!this._connectSync) {
|
||||||
this._connectSync = Meteor.wrapAsync(this.connectAsync, this);
|
this._connectSync = Meteor.wrapAsync(this.connectAsync, this);
|
||||||
|
|
@ -60,6 +64,7 @@ export default class LDAP {
|
||||||
}
|
}
|
||||||
|
|
||||||
searchAllSync(...args) {
|
searchAllSync(...args) {
|
||||||
|
|
||||||
if (!this._searchAllSync) {
|
if (!this._searchAllSync) {
|
||||||
this._searchAllSync = Meteor.wrapAsync(this.searchAllAsync, this);
|
this._searchAllSync = Meteor.wrapAsync(this.searchAllAsync, this);
|
||||||
}
|
}
|
||||||
|
|
@ -72,19 +77,19 @@ export default class LDAP {
|
||||||
let replied = false;
|
let replied = false;
|
||||||
|
|
||||||
const connectionOptions = {
|
const connectionOptions = {
|
||||||
url: `${ this.options.host }:${ this.options.port }`,
|
url : `${this.options.host}:${this.options.port}`,
|
||||||
timeout: this.options.timeout,
|
timeout : this.options.timeout,
|
||||||
connectTimeout: this.options.connect_timeout,
|
connectTimeout: this.options.connect_timeout,
|
||||||
idleTimeout: this.options.idle_timeout,
|
idleTimeout : this.options.idle_timeout,
|
||||||
reconnect: this.options.Reconnect,
|
reconnect : this.options.Reconnect,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.options.Internal_Log_Level !== 'disabled') {
|
if (this.options.Internal_Log_Level !== 'disabled') {
|
||||||
connectionOptions.log = new Bunyan({
|
connectionOptions.log = new Bunyan({
|
||||||
name: 'ldapjs',
|
name : 'ldapjs',
|
||||||
component: 'client',
|
component: 'client',
|
||||||
stream: process.stderr,
|
stream : process.stderr,
|
||||||
level: this.options.Internal_Log_Level,
|
level : this.options.Internal_Log_Level,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,14 +113,14 @@ export default class LDAP {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.encryption === 'ssl') {
|
if (this.options.encryption === 'ssl') {
|
||||||
connectionOptions.url = `ldaps://${ connectionOptions.url }`;
|
connectionOptions.url = `ldaps://${connectionOptions.url}`;
|
||||||
connectionOptions.tlsOptions = tlsOptions;
|
connectionOptions.tlsOptions = tlsOptions;
|
||||||
} else {
|
} else {
|
||||||
connectionOptions.url = `ldap://${ connectionOptions.url }`;
|
connectionOptions.url = `ldap://${connectionOptions.url}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info('Connecting', connectionOptions.url);
|
log_info('Connecting', connectionOptions.url);
|
||||||
log_debug(`connectionOptions${ util.inspect(connectionOptions)}`);
|
log_debug(`connectionOptions${util.inspect(connectionOptions)}`);
|
||||||
|
|
||||||
this.client = ldapjs.createClient(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 !== '') {
|
||||||
if (this.options.User_Search_Filter[0] === '(') {
|
if (this.options.User_Search_Filter[0] === '(') {
|
||||||
filter.push(`${ this.options.User_Search_Filter }`);
|
filter.push(`${this.options.User_Search_Filter}`);
|
||||||
} else {
|
} 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) {
|
if (usernameFilter.length === 0) {
|
||||||
log_error('LDAP_LDAP_User_Search_Field not defined');
|
log_error('LDAP_LDAP_User_Search_Field not defined');
|
||||||
} else if (usernameFilter.length === 1) {
|
} else if (usernameFilter.length === 1) {
|
||||||
filter.push(`${ usernameFilter[0] }`);
|
filter.push(`${usernameFilter[0]}`);
|
||||||
} else {
|
} else {
|
||||||
filter.push(`(|${ usernameFilter.join('') })`);
|
filter.push(`(|${usernameFilter.join('')})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return `(&${ filter.join('') })`;
|
return `(&${filter.join('')})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
bindUserIfNecessary(username, password) {
|
||||||
|
|
||||||
|
if (this.domainBinded === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.options.User_Authentication) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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() {
|
bindIfNecessary() {
|
||||||
|
|
@ -218,22 +242,24 @@ export default class LDAP {
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info('Binding UserDN', this.options.Authentication_UserDN);
|
log_info('Binding UserDN', this.options.Authentication_UserDN);
|
||||||
|
|
||||||
this.bindSync(this.options.Authentication_UserDN, this.options.Authentication_Password);
|
this.bindSync(this.options.Authentication_UserDN, this.options.Authentication_Password);
|
||||||
this.domainBinded = true;
|
this.domainBinded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
searchUsersSync(username, page) {
|
searchUsersSync(username, page) {
|
||||||
this.bindIfNecessary();
|
this.bindIfNecessary();
|
||||||
|
|
||||||
const searchOptions = {
|
const searchOptions = {
|
||||||
filter: this.getUserFilter(username),
|
filter : this.getUserFilter(username),
|
||||||
scope: this.options.User_Search_Scope || 'sub',
|
scope : this.options.User_Search_Scope || 'sub',
|
||||||
sizeLimit: this.options.Search_Size_Limit,
|
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) {
|
if (this.options.Search_Page_Size > 0) {
|
||||||
searchOptions.paged = {
|
searchOptions.paged = {
|
||||||
pageSize: this.options.Search_Page_Size,
|
pageSize : this.options.Search_Page_Size,
|
||||||
pagePause: !!page,
|
pagePause: !!page,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -266,11 +292,11 @@ export default class LDAP {
|
||||||
Unique_Identifier_Field.forEach((item) => {
|
Unique_Identifier_Field.forEach((item) => {
|
||||||
filters.push(new this.ldapjs.filters.EqualityFilter({
|
filters.push(new this.ldapjs.filters.EqualityFilter({
|
||||||
attribute: item,
|
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 = {
|
const searchOptions = {
|
||||||
|
|
@ -300,7 +326,7 @@ export default class LDAP {
|
||||||
|
|
||||||
const searchOptions = {
|
const searchOptions = {
|
||||||
filter: this.getUserFilter(username),
|
filter: this.getUserFilter(username),
|
||||||
scope: this.options.User_Search_Scope || 'sub',
|
scope : this.options.User_Search_Scope || 'sub',
|
||||||
};
|
};
|
||||||
|
|
||||||
log_info('Searching user', username);
|
log_info('Searching user', username);
|
||||||
|
|
@ -320,7 +346,7 @@ export default class LDAP {
|
||||||
return result[0];
|
return result[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
getUserGroups(username, ldapUser){
|
getUserGroups(username, ldapUser) {
|
||||||
if (!this.options.group_filter_enabled) {
|
if (!this.options.group_filter_enabled) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -328,13 +354,13 @@ export default class LDAP {
|
||||||
const filter = ['(&'];
|
const filter = ['(&'];
|
||||||
|
|
||||||
if (this.options.group_filter_object_class !== '') {
|
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 !== '') {
|
if (this.options.group_filter_group_member_attribute !== '') {
|
||||||
const format_value = ldapUser[this.options.group_filter_group_member_format];
|
const format_value = ldapUser[this.options.group_filter_group_member_format];
|
||||||
if( format_value ) {
|
if (format_value) {
|
||||||
filter.push(`(${ this.options.group_filter_group_member_attribute }=${ format_value })`);
|
filter.push(`(${this.options.group_filter_group_member_attribute}=${format_value})`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -342,7 +368,7 @@ export default class LDAP {
|
||||||
|
|
||||||
const searchOptions = {
|
const searchOptions = {
|
||||||
filter: filter.join('').replace(/#{username}/g, username),
|
filter: filter.join('').replace(/#{username}/g, username),
|
||||||
scope: 'sub',
|
scope : 'sub',
|
||||||
};
|
};
|
||||||
|
|
||||||
log_debug('Group list filter LDAP:', searchOptions.filter);
|
log_debug('Group list filter LDAP:', searchOptions.filter);
|
||||||
|
|
@ -356,9 +382,9 @@ export default class LDAP {
|
||||||
const grp_identifier = this.options.group_filter_group_id_attribute || 'cn';
|
const grp_identifier = this.options.group_filter_group_id_attribute || 'cn';
|
||||||
const groups = [];
|
const groups = [];
|
||||||
result.map((item) => {
|
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;
|
return groups;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -373,24 +399,24 @@ export default class LDAP {
|
||||||
const filter = ['(&'];
|
const filter = ['(&'];
|
||||||
|
|
||||||
if (this.options.group_filter_object_class !== '') {
|
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 !== '') {
|
if (this.options.group_filter_group_member_attribute !== '') {
|
||||||
const format_value = ldapUser[this.options.group_filter_group_member_format];
|
const format_value = ldapUser[this.options.group_filter_group_member_format];
|
||||||
if( format_value ) {
|
if (format_value) {
|
||||||
filter.push(`(${ this.options.group_filter_group_member_attribute }=${ format_value })`);
|
filter.push(`(${this.options.group_filter_group_member_attribute}=${format_value})`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.group_filter_group_id_attribute !== '') {
|
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(')');
|
filter.push(')');
|
||||||
|
|
||||||
const searchOptions = {
|
const searchOptions = {
|
||||||
filter: filter.join('').replace(/#{username}/g, username),
|
filter: filter.join('').replace(/#{username}/g, username),
|
||||||
scope: 'sub',
|
scope : 'sub',
|
||||||
};
|
};
|
||||||
|
|
||||||
log_debug('Group filter LDAP:', searchOptions.filter);
|
log_debug('Group filter LDAP:', searchOptions.filter);
|
||||||
|
|
@ -426,15 +452,17 @@ export default class LDAP {
|
||||||
searchAllPaged(BaseDN, options, page) {
|
searchAllPaged(BaseDN, options, page) {
|
||||||
this.bindIfNecessary();
|
this.bindIfNecessary();
|
||||||
|
|
||||||
const processPage = ({entries, title, end, next}) => {
|
const processPage = ({ entries, title, end, next }) => {
|
||||||
log_info(title);
|
log_info(title);
|
||||||
// Force LDAP idle to wait the record processing
|
// Force LDAP idle to wait the record processing
|
||||||
this.client._updateIdle(true);
|
this.client._updateIdle(true);
|
||||||
page(null, entries, {end, next: () => {
|
page(null, entries, {
|
||||||
|
end, next: () => {
|
||||||
// Reset idle timer
|
// Reset idle timer
|
||||||
this.client._updateIdle();
|
this.client._updateIdle();
|
||||||
next && next();
|
next && next();
|
||||||
}});
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.client.search(BaseDN, options, (error, res) => {
|
this.client.search(BaseDN, options, (error, res) => {
|
||||||
|
|
@ -461,7 +489,7 @@ export default class LDAP {
|
||||||
processPage({
|
processPage({
|
||||||
entries,
|
entries,
|
||||||
title: 'Internal Page',
|
title: 'Internal Page',
|
||||||
end: false,
|
end : false,
|
||||||
});
|
});
|
||||||
entries = [];
|
entries = [];
|
||||||
}
|
}
|
||||||
|
|
@ -473,14 +501,14 @@ export default class LDAP {
|
||||||
processPage({
|
processPage({
|
||||||
entries,
|
entries,
|
||||||
title: 'Final Page',
|
title: 'Final Page',
|
||||||
end: true,
|
end : true,
|
||||||
});
|
});
|
||||||
} else if (entries.length) {
|
} else if (entries.length) {
|
||||||
log_info('Page');
|
log_info('Page');
|
||||||
processPage({
|
processPage({
|
||||||
entries,
|
entries,
|
||||||
title: 'Page',
|
title: 'Page',
|
||||||
end: false,
|
end : false,
|
||||||
next,
|
next,
|
||||||
});
|
});
|
||||||
entries = [];
|
entries = [];
|
||||||
|
|
@ -492,7 +520,7 @@ export default class LDAP {
|
||||||
processPage({
|
processPage({
|
||||||
entries,
|
entries,
|
||||||
title: 'Final Page',
|
title: 'Final Page',
|
||||||
end: true,
|
end : true,
|
||||||
});
|
});
|
||||||
entries = [];
|
entries = [];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue