merge userdb.js into users.js
This commit is contained in:
+99
-112
@@ -56,7 +56,9 @@ function getUsersWithAccessToApp(req, callback) {
|
||||
assert.strictEqual(typeof req.app, 'object');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
users.getAll(function (error, result) {
|
||||
const getAllUsers = util.callbackify(users.getAll);
|
||||
|
||||
getAllUsers(function (error, result) {
|
||||
if (error) return callback(new ldap.OperationsError(error.toString()));
|
||||
|
||||
async.filter(result, apps.hasAccessTo.bind(null, req.app), function (error, allowedUsers) {
|
||||
@@ -331,53 +333,45 @@ function mailboxSearch(req, res, next) {
|
||||
finalSend(results, req, res, next);
|
||||
});
|
||||
} else { // new sogo
|
||||
mailboxdb.listAllMailboxes(1, 1000, function (error, mailboxes) {
|
||||
mailboxdb.listAllMailboxes(1, 1000, async function (error, mailboxes) {
|
||||
if (error) return next(new ldap.OperationsError(error.toString()));
|
||||
|
||||
mailboxes = mailboxes.filter(m => m.active);
|
||||
|
||||
let results = [];
|
||||
|
||||
// send mailbox objects
|
||||
async.eachSeries(mailboxes, function (mailbox, callback) {
|
||||
var dn = ldap.parseDN(`cn=${mailbox.name}@${mailbox.domain},ou=mailboxes,dc=cloudron`);
|
||||
for (const mailbox of mailboxes) {
|
||||
const dn = ldap.parseDN(`cn=${mailbox.name}@${mailbox.domain},ou=mailboxes,dc=cloudron`);
|
||||
|
||||
let getFunc = mailbox.ownerType === mail.OWNERTYPE_USER ? users.get : groups.get;
|
||||
const [error, ownerObject] = await safe(mailbox.ownerType === mail.OWNERTYPE_USER ? users.get(mailbox.ownerId) : groups.get(mailbox.ownerId));
|
||||
if (error || !ownerObject) continue; // skip mailboxes with unknown user
|
||||
|
||||
getFunc(mailbox.ownerId, function (error, ownerObject) {
|
||||
if (error) return callback(); // skip mailboxes with unknown owner
|
||||
|
||||
var obj = {
|
||||
dn: dn.toString(),
|
||||
attributes: {
|
||||
objectclass: ['mailbox'],
|
||||
objectcategory: 'mailbox',
|
||||
displayname: mailbox.ownerType === mail.OWNERTYPE_USER ? ownerObject.displayName : ownerObject.name,
|
||||
cn: `${mailbox.name}@${mailbox.domain}`,
|
||||
uid: `${mailbox.name}@${mailbox.domain}`,
|
||||
mail: `${mailbox.name}@${mailbox.domain}`
|
||||
}
|
||||
};
|
||||
|
||||
mailbox.aliases.forEach(function (a, idx) {
|
||||
obj.attributes['mail' + idx] = `${a.name}@${a.domain}`;
|
||||
});
|
||||
|
||||
// ensure all filter values are also lowercase
|
||||
var lowerCaseFilter = safe(function () { return ldap.parseFilter(req.filter.toString().toLowerCase()); }, null);
|
||||
if (!lowerCaseFilter) return next(new ldap.OperationsError(safe.error.toString()));
|
||||
|
||||
if ((req.dn.equals(dn) || req.dn.parentOf(dn)) && lowerCaseFilter.matches(obj.attributes)) {
|
||||
results.push(obj);
|
||||
const obj = {
|
||||
dn: dn.toString(),
|
||||
attributes: {
|
||||
objectclass: ['mailbox'],
|
||||
objectcategory: 'mailbox',
|
||||
displayname: mailbox.ownerType === mail.OWNERTYPE_USER ? ownerObject.displayName : ownerObject.name,
|
||||
cn: `${mailbox.name}@${mailbox.domain}`,
|
||||
uid: `${mailbox.name}@${mailbox.domain}`,
|
||||
mail: `${mailbox.name}@${mailbox.domain}`
|
||||
}
|
||||
};
|
||||
|
||||
callback();
|
||||
mailbox.aliases.forEach(function (a, idx) {
|
||||
obj.attributes['mail' + idx] = `${a.name}@${a.domain}`;
|
||||
});
|
||||
}, function (error) {
|
||||
if (error) return next(new ldap.OperationsError(error.toString()));
|
||||
|
||||
finalSend(results, req, res, next);
|
||||
});
|
||||
// ensure all filter values are also lowercase
|
||||
const lowerCaseFilter = safe(function () { return ldap.parseFilter(req.filter.toString().toLowerCase()); }, null);
|
||||
if (!lowerCaseFilter) return next(new ldap.OperationsError(safe.error.toString()));
|
||||
|
||||
if ((req.dn.equals(dn) || req.dn.parentOf(dn)) && lowerCaseFilter.matches(obj.attributes)) {
|
||||
results.push(obj);
|
||||
}
|
||||
}
|
||||
|
||||
finalSend(results, req, res, next);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -465,34 +459,33 @@ function mailingListSearch(req, res, next) {
|
||||
}
|
||||
|
||||
// Will attach req.user if successful
|
||||
function authenticateUser(req, res, next) {
|
||||
async function authenticateUser(req, res, next) {
|
||||
debug('user bind: %s (from %s)', req.dn.toString(), req.connection.ldap.id);
|
||||
|
||||
// extract the common name which might have different attribute names
|
||||
var attributeName = Object.keys(req.dn.rdns[0].attrs)[0];
|
||||
var commonName = req.dn.rdns[0].attrs[attributeName].value;
|
||||
const attributeName = Object.keys(req.dn.rdns[0].attrs)[0];
|
||||
const commonName = req.dn.rdns[0].attrs[attributeName].value;
|
||||
if (!commonName) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
|
||||
var api;
|
||||
let verifyFunc;
|
||||
if (attributeName === 'mail') {
|
||||
api = users.verifyWithEmail;
|
||||
verifyFunc = users.verifyWithEmail;
|
||||
} else if (commonName.indexOf('@') !== -1) { // if mail is specified, enforce mail check
|
||||
api = users.verifyWithEmail;
|
||||
verifyFunc = users.verifyWithEmail;
|
||||
} else if (commonName.indexOf('uid-') === 0) {
|
||||
api = users.verify;
|
||||
verifyFunc = users.verify;
|
||||
} else {
|
||||
api = users.verifyWithUsername;
|
||||
verifyFunc = users.verifyWithUsername;
|
||||
}
|
||||
|
||||
api(commonName, req.credentials || '', req.app.id, function (error, user) {
|
||||
if (error && error.reason === BoxError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
if (error && error.reason === BoxError.INVALID_CREDENTIALS) return next(new ldap.InvalidCredentialsError(req.dn.toString()));
|
||||
if (error) return next(new ldap.OperationsError(error.message));
|
||||
const [error, user] = await safe(verifyFunc(commonName, req.credentials || '', req.app.id));
|
||||
if (error && error.reason === BoxError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
if (error && error.reason === BoxError.INVALID_CREDENTIALS) return next(new ldap.InvalidCredentialsError(req.dn.toString()));
|
||||
if (error) return next(new ldap.OperationsError(error.message));
|
||||
|
||||
req.user = user;
|
||||
req.user = user;
|
||||
|
||||
next();
|
||||
});
|
||||
next();
|
||||
}
|
||||
|
||||
function authorizeUserForApp(req, res, next) {
|
||||
@@ -511,27 +504,24 @@ function authorizeUserForApp(req, res, next) {
|
||||
});
|
||||
}
|
||||
|
||||
async function verifyMailboxPassword(mailbox, password, callback) {
|
||||
async function verifyMailboxPassword(mailbox, password) {
|
||||
assert.strictEqual(typeof mailbox, 'object');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
if (mailbox.ownerType === mail.OWNERTYPE_USER) return users.verify(mailbox.ownerId, password, users.AP_MAIL /* identifier */, callback);
|
||||
if (mailbox.ownerType === mail.OWNERTYPE_USER) return await users.verify(mailbox.ownerId, password, users.AP_MAIL /* identifier */);
|
||||
|
||||
const [error, userIds] = await safe(groups.getMembers(mailbox.ownerId));
|
||||
if (error) return callback(error);
|
||||
const userIds = await groups.getMembers(mailbox.ownerId);
|
||||
|
||||
let verifiedUser = null;
|
||||
async.someSeries(userIds, function iterator(userId, iteratorDone) {
|
||||
users.verify(userId, password, users.AP_MAIL /* identifier */, function (error, result) {
|
||||
if (error) return iteratorDone(null, false);
|
||||
verifiedUser = result;
|
||||
iteratorDone(null, true);
|
||||
});
|
||||
}, function (error, result) {
|
||||
if (!result) return callback(new BoxError(BoxError.INVALID_CREDENTIALS));
|
||||
callback(null, verifiedUser);
|
||||
});
|
||||
for (const userId of userIds) {
|
||||
const [error, result] = await safe(users.verify(userId, password, users.AP_MAIL /* identifier */));
|
||||
if (error) continue; // try the next user
|
||||
verifiedUser = result;
|
||||
break; // found a matching validated user
|
||||
}
|
||||
|
||||
if (!verifiedUser) throw new BoxError(BoxError.INVALID_CREDENTIALS);
|
||||
return verifiedUser;
|
||||
}
|
||||
|
||||
function authenticateUserMailbox(req, res, next) {
|
||||
@@ -551,21 +541,20 @@ function authenticateUserMailbox(req, res, next) {
|
||||
|
||||
if (!domain.enabled) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
|
||||
mailboxdb.getMailbox(parts[0], parts[1], function (error, mailbox) {
|
||||
mailboxdb.getMailbox(parts[0], parts[1], async function (error, mailbox) {
|
||||
if (error && error.reason === BoxError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
if (error) return next(new ldap.OperationsError(error.message));
|
||||
|
||||
if (!mailbox.active) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
|
||||
verifyMailboxPassword(mailbox, req.credentials || '', async function (error, result) {
|
||||
if (error && error.reason === BoxError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
if (error && error.reason === BoxError.INVALID_CREDENTIALS) return next(new ldap.InvalidCredentialsError(req.dn.toString()));
|
||||
if (error) return next(new ldap.OperationsError(error.message));
|
||||
const [verifyError, result] = await safe(verifyMailboxPassword(mailbox, req.credentials || ''));
|
||||
if (verifyError && verifyError.reason === BoxError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
if (verifyError && verifyError.reason === BoxError.INVALID_CREDENTIALS) return next(new ldap.InvalidCredentialsError(req.dn.toString()));
|
||||
if (verifyError) return next(new ldap.OperationsError(verifyError.message));
|
||||
|
||||
eventlog.upsertLoginEvent(eventlog.ACTION_USER_LOGIN, { authType: 'ldap', mailboxId: email }, { userId: result.id, user: users.removePrivateFields(result) });
|
||||
eventlog.upsertLoginEvent(eventlog.ACTION_USER_LOGIN, { authType: 'ldap', mailboxId: email }, { userId: result.id, user: users.removePrivateFields(result) });
|
||||
|
||||
res.end();
|
||||
});
|
||||
res.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -575,20 +564,19 @@ function authenticateSftp(req, res, next) {
|
||||
|
||||
if (!req.dn.rdns[0].attrs.cn) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
|
||||
var email = req.dn.rdns[0].attrs.cn.value.toLowerCase();
|
||||
var parts = email.split('@');
|
||||
const email = req.dn.rdns[0].attrs.cn.value.toLowerCase();
|
||||
const parts = email.split('@');
|
||||
if (parts.length !== 2) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
|
||||
apps.getByFqdn(parts[1], function (error, app) {
|
||||
apps.getByFqdn(parts[1], async function (error, app) {
|
||||
if (error) return next(new ldap.InvalidCredentialsError(req.dn.toString()));
|
||||
|
||||
users.verifyWithUsername(parts[0], req.credentials, app.id, function (error) {
|
||||
if (error) return next(new ldap.InvalidCredentialsError(req.dn.toString()));
|
||||
[error] = await safe(users.verifyWithUsername(parts[0], req.credentials, app.id));
|
||||
if (error) return next(new ldap.InvalidCredentialsError(req.dn.toString()));
|
||||
|
||||
debug('sftp auth: success');
|
||||
debug('sftp auth: success');
|
||||
|
||||
res.end();
|
||||
});
|
||||
res.end();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -613,7 +601,7 @@ function userSearchSftp(req, res, next) {
|
||||
var username = parts[0];
|
||||
var appFqdn = parts[1];
|
||||
|
||||
apps.getByFqdn(appFqdn, function (error, app) {
|
||||
apps.getByFqdn(appFqdn, async function (error, app) {
|
||||
if (error) return next(new ldap.OperationsError(error.toString()));
|
||||
|
||||
// only allow apps which specify "ftp" support in the localstorage addon
|
||||
@@ -622,30 +610,30 @@ function userSearchSftp(req, res, next) {
|
||||
|
||||
const uidNumber = app.manifest.addons.localstorage.ftp.uid;
|
||||
|
||||
users.getByUsername(username, function (error, user) {
|
||||
const [userGetError, user] = await users.getByUsername(username);
|
||||
if (userGetError) return next(new ldap.OperationsError(userGetError.toString()));
|
||||
if (!user) return next(new ldap.OperationsError('Invalid username'));
|
||||
|
||||
if (req.requireAdmin && users.compareRoles(user.role, users.ROLE_ADMIN) < 0) return next(new ldap.InsufficientAccessRightsError('Insufficient previleges'));
|
||||
|
||||
apps.hasAccessTo(app, user, function (error, hasAccess) {
|
||||
if (error) return next(new ldap.OperationsError(error.toString()));
|
||||
if (!hasAccess) return next(new ldap.InsufficientAccessRightsError('Not authorized'));
|
||||
|
||||
if (req.requireAdmin && users.compareRoles(user.role, users.ROLE_ADMIN) < 0) return next(new ldap.InsufficientAccessRightsError('Insufficient previleges'));
|
||||
var obj = {
|
||||
dn: ldap.parseDN(`cn=${username}@${appFqdn},ou=sftp,dc=cloudron`).toString(),
|
||||
attributes: {
|
||||
homeDirectory: app.dataDir ? `/mnt/${app.id}` : `/mnt/appsdata/${app.id}/data`,
|
||||
objectclass: ['user'],
|
||||
objectcategory: 'person',
|
||||
cn: user.id,
|
||||
uid: `${username}@${appFqdn}`, // for bind after search
|
||||
uidNumber: uidNumber, // unix uid for ftp access
|
||||
gidNumber: uidNumber // unix gid for ftp access
|
||||
}
|
||||
};
|
||||
|
||||
apps.hasAccessTo(app, user, function (error, hasAccess) {
|
||||
if (error) return next(new ldap.OperationsError(error.toString()));
|
||||
if (!hasAccess) return next(new ldap.InsufficientAccessRightsError('Not authorized'));
|
||||
|
||||
var obj = {
|
||||
dn: ldap.parseDN(`cn=${username}@${appFqdn},ou=sftp,dc=cloudron`).toString(),
|
||||
attributes: {
|
||||
homeDirectory: app.dataDir ? `/mnt/${app.id}` : `/mnt/appsdata/${app.id}/data`,
|
||||
objectclass: ['user'],
|
||||
objectcategory: 'person',
|
||||
cn: user.id,
|
||||
uid: `${username}@${appFqdn}`, // for bind after search
|
||||
uidNumber: uidNumber, // unix uid for ftp access
|
||||
gidNumber: uidNumber // unix gid for ftp access
|
||||
}
|
||||
};
|
||||
|
||||
finalSend([ obj ], req, res, next);
|
||||
});
|
||||
finalSend([ obj ], req, res, next);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -696,21 +684,20 @@ function authenticateMailAddon(req, res, next) {
|
||||
if (error && error.reason === BoxError.INVALID_CREDENTIALS) return next(new ldap.InvalidCredentialsError(req.dn.toString()));
|
||||
if (error && error.reason !== BoxError.NOT_FOUND) return next(new ldap.OperationsError(error.message));
|
||||
|
||||
mailboxdb.getMailbox(parts[0], parts[1], function (error, mailbox) {
|
||||
mailboxdb.getMailbox(parts[0], parts[1], async function (error, mailbox) {
|
||||
if (error && error.reason === BoxError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
if (error) return next(new ldap.OperationsError(error.message));
|
||||
|
||||
if (!mailbox.active) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
|
||||
verifyMailboxPassword(mailbox, req.credentials || '', async function (error, result) {
|
||||
if (error && error.reason === BoxError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
if (error && error.reason === BoxError.INVALID_CREDENTIALS) return next(new ldap.InvalidCredentialsError(req.dn.toString()));
|
||||
if (error) return next(new ldap.OperationsError(error.message));
|
||||
const [verifyError, result] = await safe(verifyMailboxPassword(mailbox, req.credentials || ''));
|
||||
if (verifyError && verifyError.reason === BoxError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
if (verifyError && verifyError.reason === BoxError.INVALID_CREDENTIALS) return next(new ldap.InvalidCredentialsError(req.dn.toString()));
|
||||
if (verifyError) return next(new ldap.OperationsError(verifyError.message));
|
||||
|
||||
eventlog.upsertLoginEvent(eventlog.ACTION_USER_LOGIN, { authType: 'ldap', mailboxId: email }, { userId: result.id, user: users.removePrivateFields(result) });
|
||||
eventlog.upsertLoginEvent(eventlog.ACTION_USER_LOGIN, { authType: 'ldap', mailboxId: email }, { userId: result.id, user: users.removePrivateFields(result) });
|
||||
|
||||
res.end();
|
||||
});
|
||||
res.end();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user