diff options
Diffstat (limited to '.sandstorm-meteor-1.8/ldap.js')
-rw-r--r-- | .sandstorm-meteor-1.8/ldap.js | 640 |
1 files changed, 0 insertions, 640 deletions
diff --git a/.sandstorm-meteor-1.8/ldap.js b/.sandstorm-meteor-1.8/ldap.js deleted file mode 100644 index 3b963823..00000000 --- a/.sandstorm-meteor-1.8/ldap.js +++ /dev/null @@ -1,640 +0,0 @@ -import ldapjs from 'ldapjs'; -import util from 'util'; -import Bunyan from 'bunyan'; -import { log_debug, log_info, log_warn, log_error } from './logger'; - -export default class LDAP { - 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_Authentication: this.constructor.settings_get( - 'LDAP_USER_AUTHENTICATION', - ), - User_Authentication_Field: this.constructor.settings_get( - 'LDAP_USER_AUTHENTICATION_FIELD', - ), - 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', - ), - }; - } - - static settings_get(name, ...args) { - let value = process.env[name]; - if (value !== undefined) { - if (value === 'true' || value === 'false') { - value = JSON.parse(value); - } else if (value !== '' && !isNaN(value)) { - value = Number(value); - } - return value; - } else { - log_warn(`Lookup for unset variable: ${name}`); - } - } - - connectSync(...args) { - 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); - } - return this._searchAllSync(...args); - } - - connectAsync(callback) { - log_info('Init setup'); - - let replied = false; - - const connectionOptions = { - 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, - }; - - if (this.options.Internal_Log_Level !== 'disabled') { - connectionOptions.log = new Bunyan({ - name: 'ldapjs', - component: 'client', - stream: process.stderr, - level: this.options.Internal_Log_Level, - }); - } - - const tlsOptions = { - rejectUnauthorized: this.options.reject_unauthorized, - }; - - 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 = []; - chainLines.forEach(line => { - cert.push(line); - if (line.match(/-END CERTIFICATE-/)) { - ca.push(cert.join('\n')); - cert = []; - } - }); - tlsOptions.ca = ca; - } - - if (this.options.encryption === 'ssl') { - connectionOptions.url = `ldaps://${connectionOptions.url}`; - connectionOptions.tlsOptions = tlsOptions; - } else { - connectionOptions.url = `ldap://${connectionOptions.url}`; - } - - log_info('Connecting', connectionOptions.url); - log_debug(`connectionOptions${util.inspect(connectionOptions)}`); - - this.client = ldapjs.createClient(connectionOptions); - - this.bindSync = Meteor.wrapAsync(this.client.bind, this.client); - - this.client.on('error', error => { - log_error('connection', error); - if (replied === false) { - replied = true; - callback(error, null); - } - }); - - this.client.on('idle', () => { - log_info('Idle'); - this.disconnect(); - }); - - this.client.on('close', () => { - log_info('Closed'); - }); - - if (this.options.encryption === 'tls') { - // Set host parameter for tls.connect which is used by ldapjs starttls. This shouldn't be needed in newer nodejs versions (e.g v5.6.0). - // https://github.com/RocketChat/Rocket.Chat/issues/2035 - // https://github.com/mcavage/node-ldapjs/issues/349 - tlsOptions.host = this.options.host; - - log_info('Starting TLS'); - log_debug('tlsOptions', tlsOptions); - - this.client.starttls(tlsOptions, null, (error, response) => { - if (error) { - log_error('TLS connection', error); - if (replied === false) { - replied = true; - callback(error, null); - } - return; - } - - log_info('TLS connected'); - this.connected = true; - if (replied === false) { - replied = true; - callback(null, response); - } - }); - } else { - this.client.on('connect', response => { - log_info('LDAP connected'); - this.connected = true; - if (replied === false) { - replied = true; - callback(null, response); - } - }); - } - - setTimeout(() => { - if (replied === false) { - log_error('connection time out', connectionOptions.connectTimeout); - replied = true; - callback(new Error('Timeout')); - } - }, connectionOptions.connectTimeout); - } - - getUserFilter(username) { - const filter = []; - - if (this.options.User_Search_Filter !== '') { - if (this.options.User_Search_Filter[0] === '(') { - filter.push(`${this.options.User_Search_Filter}`); - } else { - filter.push(`(${this.options.User_Search_Filter})`); - } - } - - 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]}`); - } else { - filter.push(`(|${usernameFilter.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 = `${this.options.User_Authentication_Field}=${username},${this.options.BaseDN}`; - - this.bindSync(userDn, password); - this.domainBinded = true; - } - - bindIfNecessary() { - if (this.domainBinded === true) { - return; - } - - if (this.options.Authentication !== true) { - return; - } - - 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', - 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, - pagePause: !!page, - }; - } - - log_info('Searching user', username); - log_debug('searchOptions', searchOptions); - log_debug('BaseDN', this.options.BaseDN); - - if (page) { - return this.searchAllPaged(this.options.BaseDN, searchOptions, page); - } - - return this.searchAllSync(this.options.BaseDN, searchOptions); - } - - getUserByIdSync(id, attribute) { - this.bindIfNecessary(); - - const Unique_Identifier_Field = this.constructor - .settings_get('LDAP_UNIQUE_IDENTIFIER_FIELD') - .split(','); - - let filter; - - if (attribute) { - filter = new this.ldapjs.filters.EqualityFilter({ - attribute, - value: new Buffer(id, 'hex'), - }); - } else { - const filters = []; - Unique_Identifier_Field.forEach(item => { - filters.push( - new this.ldapjs.filters.EqualityFilter({ - attribute: item, - value: new Buffer(id, 'hex'), - }), - ); - }); - - filter = new this.ldapjs.filters.OrFilter({ filters }); - } - - const searchOptions = { - filter, - scope: 'sub', - }; - - log_info('Searching by id', id); - log_debug('search filter', searchOptions.filter.toString()); - log_debug('BaseDN', this.options.BaseDN); - - const result = this.searchAllSync(this.options.BaseDN, searchOptions); - - if (!Array.isArray(result) || result.length === 0) { - return; - } - - if (result.length > 1) { - log_error('Search by id', id, 'returned', result.length, 'records'); - } - - return result[0]; - } - - getUserByUsernameSync(username) { - this.bindIfNecessary(); - - const searchOptions = { - filter: this.getUserFilter(username), - scope: this.options.User_Search_Scope || 'sub', - }; - - log_info('Searching user', username); - log_debug('searchOptions', searchOptions); - log_debug('BaseDN', this.options.BaseDN); - - const result = this.searchAllSync(this.options.BaseDN, searchOptions); - - if (!Array.isArray(result) || result.length === 0) { - return; - } - - if (result.length > 1) { - log_error( - 'Search by username', - username, - 'returned', - result.length, - 'records', - ); - } - - return result[0]; - } - - getUserGroups(username, ldapUser) { - if (!this.options.group_filter_enabled) { - return true; - } - - const filter = ['(&']; - - if (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})`, - ); - } - } - - filter.push(')'); - - const searchOptions = { - filter: filter.join('').replace(/#{username}/g, username), - scope: 'sub', - }; - - log_debug('Group list filter LDAP:', searchOptions.filter); - - const result = this.searchAllSync(this.options.BaseDN, searchOptions); - - if (!Array.isArray(result) || result.length === 0) { - return []; - } - - const grp_identifier = this.options.group_filter_group_id_attribute || 'cn'; - const groups = []; - result.map(item => { - groups.push(item[grp_identifier]); - }); - log_debug(`Groups: ${groups.join(', ')}`); - return groups; - } - - isUserInGroup(username, ldapUser) { - if (!this.options.group_filter_enabled) { - return true; - } - - const grps = this.getUserGroups(username, ldapUser); - - const filter = ['(&']; - - if (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 (this.options.group_filter_group_id_attribute !== '') { - 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', - }; - - log_debug('Group filter LDAP:', searchOptions.filter); - - const result = this.searchAllSync(this.options.BaseDN, searchOptions); - - if (!Array.isArray(result) || result.length === 0) { - return false; - } - return true; - } - - extractLdapEntryData(entry) { - const values = { - _raw: entry.raw, - }; - - Object.keys(values._raw).forEach(key => { - const value = values._raw[key]; - - if (!['thumbnailPhoto', 'jpegPhoto'].includes(key)) { - if (value instanceof Buffer) { - values[key] = value.toString(); - } else { - values[key] = value; - } - } - }); - - return values; - } - - searchAllPaged(BaseDN, options, page) { - this.bindIfNecessary(); - - 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(); - }, - }); - }; - - this.client.search(BaseDN, options, (error, res) => { - if (error) { - log_error(error); - page(error); - return; - } - - res.on('error', error => { - log_error(error); - page(error); - return; - }); - - let entries = []; - - const internalPageSize = - options.paged && options.paged.pageSize > 0 - ? options.paged.pageSize * 2 - : 500; - - res.on('searchEntry', entry => { - entries.push(this.extractLdapEntryData(entry)); - - if (entries.length >= internalPageSize) { - processPage({ - entries, - title: 'Internal Page', - end: false, - }); - entries = []; - } - }); - - res.on('page', (result, next) => { - if (!next) { - this.client._updateIdle(true); - processPage({ - entries, - title: 'Final Page', - end: true, - }); - } else if (entries.length) { - log_info('Page'); - processPage({ - entries, - title: 'Page', - end: false, - next, - }); - entries = []; - } - }); - - res.on('end', () => { - if (entries.length) { - processPage({ - entries, - title: 'Final Page', - end: true, - }); - entries = []; - } - }); - }); - } - - searchAllAsync(BaseDN, options, callback) { - this.bindIfNecessary(); - - this.client.search(BaseDN, options, (error, res) => { - if (error) { - log_error(error); - callback(error); - return; - } - - res.on('error', error => { - log_error(error); - callback(error); - return; - }); - - const entries = []; - - res.on('searchEntry', entry => { - entries.push(this.extractLdapEntryData(entry)); - }); - - res.on('end', () => { - log_info('Search result count', entries.length); - callback(null, entries); - }); - }); - } - - authSync(dn, password) { - log_info('Authenticating', dn); - - try { - if (password === '') { - throw new Error('Password is not provided'); - } - this.bindSync(dn, password); - log_info('Authenticated', dn); - return true; - } catch (error) { - log_info('Not authenticated', dn); - log_debug('error', error); - return false; - } - } - - disconnect() { - this.connected = false; - this.domainBinded = false; - log_info('Disconecting'); - this.client.unbind(); - } -} |