Socket
Socket
Sign inDemoInstall

@mashroom/mashroom-security-provider-ldap

Package Overview
Dependencies
Maintainers
1
Versions
92
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mashroom/mashroom-security-provider-ldap - npm Package Compare versions

Comparing version 1.6.4 to 1.7.0

86

dist/LdapClientImpl.js

@@ -13,12 +13,12 @@ "use strict";

class LdapClientImpl {
constructor(serverUrl, connectTimeout, timeout, baseDN, bindDN, bindCredentials, tlsOptions, loggerFactory) {
this.serverUrl = serverUrl;
this.connectTimeout = connectTimeout;
this.timeout = timeout;
this.baseDN = baseDN;
this.bindDN = bindDN;
this.bindCredentials = bindCredentials;
this.tlsOptions = tlsOptions;
this.logger = loggerFactory('mashroom.security.provider.ldap');
this.searchClient = null;
constructor(_serverUrl, _connectTimeout, _timeout, _baseDN, _bindDN, _bindCredentials, _tlsOptions, loggerFactory) {
this._serverUrl = _serverUrl;
this._connectTimeout = _connectTimeout;
this._timeout = _timeout;
this._baseDN = _baseDN;
this._bindDN = _bindDN;
this._bindCredentials = _bindCredentials;
this._tlsOptions = _tlsOptions;
this._logger = loggerFactory('mashroom.security.provider.ldap');
this._searchClient = null;
}

@@ -45,3 +45,3 @@

const entries = [];
searchClient.search(this.baseDN, searchOpts, (err, res) => {
searchClient.search(this._baseDN, searchOpts, (err, res) => {
if (err) {

@@ -86,3 +86,4 @@ reject(err);

res.on('error', error => {
this.logger.error('LDAP search error', error);
this._logger.error('LDAP search error', error);
reject(error);

@@ -105,10 +106,10 @@ });

try {
client = await this.createLdapJsClient();
await this.bind(ldapEntry.dn, password, client);
await this.disconnect(client);
client = await this._createLdapJsClient();
await this._bind(ldapEntry.dn, password, client);
await this._disconnect(client);
} catch (error) {
this.logger.warn(`Binding with user ${ldapEntry.dn} failed`, error);
this._logger.warn(`Binding with user ${ldapEntry.dn} failed`, error);
if (client) {
await this.disconnect(client);
await this._disconnect(client);
}

@@ -121,5 +122,6 @@

shutdown() {
if (this.searchClient) {
this.disconnect(this.searchClient);
this.searchClient = null;
if (this._searchClient) {
this._disconnect(this._searchClient);
this._searchClient = null;
}

@@ -129,16 +131,17 @@ }

async getSearchClient() {
if (this.searchClient) {
return this.searchClient;
if (this._searchClient) {
return this._searchClient;
}
try {
const searchClient = await this.createLdapJsClient(true);
const searchClient = await this._createLdapJsClient(true);
const bind = async () => {
try {
await this.bind(this.bindDN, this.bindCredentials, searchClient);
await this._bind(this._bindDN, this._bindCredentials, searchClient);
} catch (error) {
this.logger.error(`Binding with user ${this.bindDN} failed`, error);
await this.disconnect(searchClient);
this.searchClient = null;
this._logger.error(`Binding with user ${this._bindDN} failed`, error);
await this._disconnect(searchClient);
this._searchClient = null;
}

@@ -152,6 +155,7 @@ };

});
this.searchClient = searchClient;
return this.searchClient;
this._searchClient = searchClient;
return this._searchClient;
} catch (error) {
this.logger.error('Creating search LDAP client failed!', error);
this._logger.error('Creating search LDAP client failed!', error);
throw error;

@@ -161,8 +165,8 @@ }

async createLdapJsClient(reconnect = false) {
async _createLdapJsClient(reconnect = false) {
const clientOptions = {
url: `${this.serverUrl}/${this.baseDN}`,
tlsOptions: this.tlsOptions,
connectTimeout: this.connectTimeout,
timeout: this.timeout
url: `${this._serverUrl}/${this._baseDN}`,
tlsOptions: this._tlsOptions,
connectTimeout: this._connectTimeout,
timeout: this._timeout
};

@@ -184,3 +188,3 @@

client.on('connect', () => {
this.logger.debug(`Connected to LDAP server: ${this.serverUrl}`);
this._logger.debug(`Connected to LDAP server: ${this._serverUrl}`);

@@ -193,3 +197,3 @@ if (!resolved) {

client.on('connectError', error => {
this.logger.error('LDAP Connection error', error);
this._logger.error('LDAP Connection error', error);

@@ -202,3 +206,3 @@ if (!resolved) {

client.on('error', error => {
this.logger.error('LDAP Error', error);
this._logger.error('LDAP Error', error);

@@ -211,3 +215,3 @@ if (!resolved) {

client.on('destroy', () => {
this.logger.debug(`Disconnected from LDAP server: ${this.serverUrl}`);
this._logger.debug(`Disconnected from LDAP server: ${this._serverUrl}`);
});

@@ -220,3 +224,3 @@ } catch (e) {

async bind(user, password, ldapjsClient) {
async _bind(user, password, ldapjsClient) {
return new Promise((resolve, reject) => {

@@ -233,3 +237,3 @@ ldapjsClient.bind(user, password, error => {

disconnect(ldapjsClient) {
_disconnect(ldapjsClient) {
if (ldapjsClient.connected) {

@@ -236,0 +240,0 @@ ldapjsClient.destroy();

@@ -22,25 +22,25 @@ "use strict";

class MashroomLdapSecurityProvider {
constructor(loginPage, userSearchFilter, groupSearchFilter, extraDataMapping, secretsMapping, groupToRoleMappingPath, userToRoleMappingPath, ldapClient, serverRootFolder, authenticationTimeoutSec, loggerFactory) {
this.loginPage = loginPage;
this.userSearchFilter = userSearchFilter;
this.groupSearchFilter = groupSearchFilter;
this.extraDataMapping = extraDataMapping;
this.secretsMapping = secretsMapping;
this.ldapClient = ldapClient;
this.serverRootFolder = serverRootFolder;
this.authenticationTimeoutSec = authenticationTimeoutSec;
constructor(_loginPage, _userSearchFilter, _groupSearchFilter, _extraDataMapping, _secretsMapping, groupToRoleMappingPath, userToRoleMappingPath, _ldapClient, _serverRootFolder, _authenticationTimeoutSec, loggerFactory) {
this._loginPage = _loginPage;
this._userSearchFilter = _userSearchFilter;
this._groupSearchFilter = _groupSearchFilter;
this._extraDataMapping = _extraDataMapping;
this._secretsMapping = _secretsMapping;
this._ldapClient = _ldapClient;
this._serverRootFolder = _serverRootFolder;
this._authenticationTimeoutSec = _authenticationTimeoutSec;
const logger = loggerFactory('mashroom.security.provider.ldap');
if (groupToRoleMappingPath) {
this.groupToRoleMappingPath = groupToRoleMappingPath;
this._groupToRoleMappingPath = groupToRoleMappingPath;
if (!_path.default.isAbsolute(groupToRoleMappingPath)) {
this.groupToRoleMappingPath = _path.default.resolve(serverRootFolder, groupToRoleMappingPath);
this._groupToRoleMappingPath = _path.default.resolve(_serverRootFolder, groupToRoleMappingPath);
}
if (this.groupToRoleMappingPath && _fs.default.existsSync(this.groupToRoleMappingPath)) {
logger.info(`Using group to role mapping: ${this.groupToRoleMappingPath}`);
if (this._groupToRoleMappingPath && _fs.default.existsSync(this._groupToRoleMappingPath)) {
logger.info(`Using group to role mapping: ${this._groupToRoleMappingPath}`);
} else {
logger.warn(`Group to role mapping file not found: ${groupToRoleMappingPath}`);
this.groupToRoleMappingPath = null;
this._groupToRoleMappingPath = null;
}

@@ -50,13 +50,13 @@ }

if (userToRoleMappingPath) {
this.userToRoleMappingPath = userToRoleMappingPath;
this._userToRoleMappingPath = userToRoleMappingPath;
if (!_path.default.isAbsolute(userToRoleMappingPath)) {
this.userToRoleMappingPath = _path.default.resolve(serverRootFolder, userToRoleMappingPath);
this._userToRoleMappingPath = _path.default.resolve(_serverRootFolder, userToRoleMappingPath);
}
if (this.userToRoleMappingPath && _fs.default.existsSync(this.userToRoleMappingPath)) {
logger.info(`Using user to role mapping: ${this.userToRoleMappingPath}`);
if (this._userToRoleMappingPath && _fs.default.existsSync(this._userToRoleMappingPath)) {
logger.info(`Using user to role mapping: ${this._userToRoleMappingPath}`);
} else {
logger.warn(`Using to role mapping file not found: ${userToRoleMappingPath}`);
this.userToRoleMappingPath = null;
this._userToRoleMappingPath = null;
}

@@ -75,3 +75,3 @@ }

response.redirect(`${this.loginPage}?redirectUrl=${encodedRedirectUrl}${authenticationHintsQuery ? `&${authenticationHintsQuery}` : ''}`);
response.redirect(`${this._loginPage}?redirectUrl=${encodedRedirectUrl}${authenticationHintsQuery ? `&${authenticationHintsQuery}` : ''}`);
return {

@@ -84,3 +84,3 @@ status: 'deferred'

if (this.getUser(request)) {
request.session[LDAP_AUTH_EXPIRES_SESSION_KEY] = Date.now() + this.authenticationTimeoutSec * 1000;
request.session[LDAP_AUTH_EXPIRES_SESSION_KEY] = Date.now() + this._authenticationTimeoutSec * 1000;
}

@@ -99,8 +99,18 @@ }

async login(request, username, password) {
const logger = request.pluginContext.loggerFactory('mashroom.security.provider.ldap');
const logger = request.pluginContext.loggerFactory('mashroom.security.provider.ldap'); // Because LDAP accepts logins with empty passwords (simple login) we need to be extra careful for
if (!(password !== null && password !== void 0 && password.trim())) {
return {
success: false,
failureReason: 'User not found'
};
}
let user = null;
const userSearchFilter = this.userSearchFilter.replace('@username@', username);
const userSearchFilter = this._userSearchFilter.replace('@username@', username);
logger.debug(`Search for users: ${userSearchFilter}`);
const extraAttributes = [...(this.secretsMapping ? Object.values(this.secretsMapping) : []), ...(this.extraDataMapping ? Object.values(this.extraDataMapping) : [])];
const users = await this.ldapClient.search(userSearchFilter, extraAttributes);
const extraAttributes = [...(this._secretsMapping ? Object.values(this._secretsMapping) : []), ...(this._extraDataMapping ? Object.values(this._extraDataMapping) : [])];
const users = await this._ldapClient.search(userSearchFilter, extraAttributes);

@@ -127,3 +137,3 @@ if (users.length > 0) {

try {
await this.ldapClient.login(user, password);
await this._ldapClient.login(user, password);
} catch (e) {

@@ -149,7 +159,7 @@ return {

if (this.extraDataMapping) {
if (this._extraDataMapping) {
extraData = {};
Object.keys(this.extraDataMapping).forEach(extraDataProp => {
if (extraData && user && this.extraDataMapping) {
extraData[extraDataProp] = user[this.extraDataMapping[extraDataProp]];
Object.keys(this._extraDataMapping).forEach(extraDataProp => {
if (extraData && user && this._extraDataMapping) {
extraData[extraDataProp] = user[this._extraDataMapping[extraDataProp]];
}

@@ -161,7 +171,7 @@ });

if (this.secretsMapping) {
if (this._secretsMapping) {
secrets = {};
Object.keys(this.secretsMapping).forEach(secretsProp => {
if (secrets && user && this.secretsMapping) {
secrets[secretsProp] = user[this.secretsMapping[secretsProp]];
Object.keys(this._secretsMapping).forEach(secretsProp => {
if (secrets && user && this._secretsMapping) {
secrets[secretsProp] = user[this._secretsMapping[secretsProp]];
}

@@ -172,3 +182,5 @@ });

const groups = await this.getUserGroups(user, logger);
const roles = this.getRoles(username, groups, logger);
const roles = this._getRoles(request, username, groups, logger);
const mashroomUser = {

@@ -186,3 +198,3 @@ username,

request.session[LDAP_AUTH_USER_SESSION_KEY] = mashroomUser;
request.session[LDAP_AUTH_EXPIRES_SESSION_KEY] = Date.now() + this.authenticationTimeoutSec * 1000;
request.session[LDAP_AUTH_EXPIRES_SESSION_KEY] = Date.now() + this._authenticationTimeoutSec * 1000;
return {

@@ -215,17 +227,17 @@ success: true

async getUserGroups(user, logger) {
if (!this.groupSearchFilter || !this.groupSearchFilter.trim()) {
if (!this._groupSearchFilter || !this._groupSearchFilter.trim()) {
return [];
}
const groupSearchFilter = `(&${this.groupSearchFilter}(member=${user.dn}))`;
const groupSearchFilter = `(&${this._groupSearchFilter}(member=${user.dn}))`;
logger.debug(`Search for user groups: ${groupSearchFilter}`);
const groupEntries = await this.ldapClient.search(groupSearchFilter);
const groupEntries = await this._ldapClient.search(groupSearchFilter);
return groupEntries.map(e => e.cn);
}
getRoles(username, groups, logger) {
_getRoles(request, username, groups, logger) {
const roles = [];
if (groups && groups.length > 0) {
const groupToRoles = this.getGroupToRoleMapping(logger);
const groupToRoles = this._getGroupToRoleMapping(request, logger);

@@ -248,3 +260,3 @@ if (groupToRoles) {

const userToRoles = this.getUserToRoleMapping(logger);
const userToRoles = this._getUserToRoleMapping(request, logger);

@@ -262,42 +274,66 @@ if (userToRoles && userToRoles.hasOwnProperty(username)) {

getGroupToRoleMapping(logger) {
if (!this.groupToRoleMappingPath) {
_getGroupToRoleMapping(request, logger) {
if (!this._groupToRoleMappingPath) {
return null;
}
if (this.groupToRoleMapping) {
return this.groupToRoleMapping;
if (this._groupToRoleMapping) {
return this._groupToRoleMapping;
}
if (_fs.default.existsSync(this.groupToRoleMappingPath)) {
this.groupToRoleMapping = require(this.groupToRoleMappingPath);
if (_fs.default.existsSync(this._groupToRoleMappingPath)) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
this._groupToRoleMapping = require(this._groupToRoleMappingPath);
this._createRoleDefinitions(this._groupToRoleMapping, request, logger);
} else {
logger.warn(`No group to roles definition found: ${this.groupToRoleMappingPath || '-'}.`);
this.groupToRoleMapping = null;
logger.warn(`No group to roles definition found: ${this._groupToRoleMappingPath || '-'}.`);
this._groupToRoleMapping = null;
}
return this.groupToRoleMapping;
return this._groupToRoleMapping;
}
getUserToRoleMapping(logger) {
if (!this.userToRoleMappingPath) {
_getUserToRoleMapping(request, logger) {
if (!this._userToRoleMappingPath) {
return null;
}
if (this.userToRoleMapping) {
return this.userToRoleMapping;
if (this._userToRoleMapping) {
return this._userToRoleMapping;
}
if (_fs.default.existsSync(this.userToRoleMappingPath)) {
this.userToRoleMapping = require(this.userToRoleMappingPath);
if (_fs.default.existsSync(this._userToRoleMappingPath)) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
this._userToRoleMapping = require(this._userToRoleMappingPath);
this._createRoleDefinitions(this._userToRoleMapping, request, logger);
} else {
logger.warn(`No user to roles definition found: ${this.userToRoleMappingPath || '-'}.`);
this.userToRoleMapping = null;
logger.warn(`No user to roles definition found: ${this._userToRoleMappingPath || '-'}.`);
this._userToRoleMapping = null;
}
return this.userToRoleMapping;
return this._userToRoleMapping;
}
async _createRoleDefinitions(mapping, request, logger) {
const securityService = request.pluginContext.services.security.service;
const roles = [];
Object.values(mapping).forEach(mappingRoles => {
mappingRoles === null || mappingRoles === void 0 ? void 0 : mappingRoles.forEach(role => {
if (roles.indexOf(role) === -1) {
roles.push(role);
}
});
});
logger.debug('Adding role definitions:', roles);
roles.forEach(id => {
securityService.addRoleDefinition(request, {
id
});
});
}
}
exports.default = MashroomLdapSecurityProvider;

@@ -7,3 +7,3 @@ {

"license": "MIT",
"version": "1.6.4",
"version": "1.7.0",
"files": [

@@ -13,17 +13,17 @@ "dist/**"

"dependencies": {
"ldapjs": "^2.2.0"
"ldapjs": "^2.2.3"
},
"devDependencies": {
"@babel/cli": "^7.12.1",
"@mashroom/mashroom": "1.6.4",
"@mashroom/mashroom-security": "1.6.4",
"@mashroom/mashroom-utils": "1.6.4",
"@types/express": "^4.17.8",
"@types/jest": "^26.0.15",
"@babel/cli": "^7.12.16",
"@mashroom/mashroom": "1.7.0",
"@mashroom/mashroom-security": "1.7.0",
"@mashroom/mashroom-utils": "1.7.0",
"@types/express": "^4.17.11",
"@types/jest": "^26.0.20",
"@types/ldapjs": "^1.0.9",
"@types/node": "14.14.6",
"eslint": "^7.13.0",
"@types/node": "14.14.28",
"eslint": "^7.19.0",
"express": "^4.17.1",
"jest": "^26.6.3",
"typescript": "^4.0.5"
"typescript": "^4.1.5"
},

@@ -52,3 +52,4 @@ "jest": {

"requires": [
"Mashroom Session Middleware"
"Mashroom Session Middleware",
"Mashroom Security Services"
],

@@ -55,0 +56,0 @@ "defaultConfig": {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc