ldap: use service ids when auth'ing email
This commit is contained in:
32
src/ldap.js
32
src/ldap.js
@@ -592,22 +592,22 @@ async function userSearchSftp(req, res, next) {
|
||||
finalSend([ obj ], req, res, next);
|
||||
}
|
||||
|
||||
async function verifyAppMailboxPassword(addonId, username, password) {
|
||||
assert.strictEqual(typeof addonId, 'string');
|
||||
async function verifyAppMailboxPassword(serviceId, username, password) {
|
||||
assert.strictEqual(typeof serviceId, 'string');
|
||||
assert.strictEqual(typeof username, 'string');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
|
||||
const pattern = addonId === 'sendmail' ? 'MAIL_SMTP' : 'MAIL_IMAP';
|
||||
const appId = await addonConfigs.getAppIdByValue(addonId, `%${pattern}_PASSWORD`, password); // search by password because this is unique for each app
|
||||
const pattern = serviceId === 'msa' ? 'MAIL_SMTP' : 'MAIL_IMAP';
|
||||
const appId = await addonConfigs.getAppIdByValue(serviceId, `%${pattern}_PASSWORD`, password); // search by password because this is unique for each app
|
||||
if (!appId) throw new BoxError(BoxError.NOT_FOUND);
|
||||
|
||||
const result = await addonConfigs.get(appId, addonId);
|
||||
const result = await addonConfigs.get(appId, serviceId);
|
||||
|
||||
if (!result.some(r => r.name.endsWith(`${pattern}_USERNAME`) && r.value === username)) throw new BoxError(BoxError.INVALID_CREDENTIALS);
|
||||
}
|
||||
|
||||
async function authenticateMailAddon(req, res, next) {
|
||||
debug('mail addon auth: %s (from %s)', req.dn.toString(), req.connection.ldap.id);
|
||||
async function authenticateMail(req, res, next) {
|
||||
debug('authenticateMail: %s (from %s)', req.dn.toString(), req.connection.ldap.id);
|
||||
|
||||
if (!req.dn.rdns[0].attrs.cn) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
|
||||
@@ -615,28 +615,29 @@ async function authenticateMailAddon(req, res, next) {
|
||||
const parts = email.split('@');
|
||||
if (parts.length !== 2) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
|
||||
const addonId = req.dn.rdns[1].attrs.ou.value.toLowerCase(); // 'sendmail' or 'recvmail'
|
||||
if (addonId !== 'sendmail' && addonId !== 'recvmail') return next(new ldap.OperationsError('Invalid DN'));
|
||||
const serviceId = req.dn.rdns[1].attrs.ou.value.toLowerCase(); // msa, imap, sieve
|
||||
if (serviceId !== 'msa' && serviceId !== 'imap' && serviceId !== 'sieve') return next(new ldap.OperationsError('Invalid DN'));
|
||||
|
||||
const [error, domain] = await safe(mail.getDomain(parts[1]));
|
||||
if (error) return next(new ldap.OperationsError(error.message));
|
||||
if (!domain) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
|
||||
if (addonId === 'recvmail' && !domain.enabled) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
const serviceNeedsMailbox = serviceId === 'imap' || serviceId === 'sieve';
|
||||
if (serviceNeedsMailbox && !domain.enabled) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
|
||||
const [getMailboxError, mailbox] = await safe(mail.getMailbox(parts[0], parts[1]));
|
||||
if (getMailboxError) return next(new ldap.OperationsError(getMailboxError.message));
|
||||
|
||||
const [appPasswordError] = await safe(verifyAppMailboxPassword(addonId, email, req.credentials || ''));
|
||||
const [appPasswordError] = await safe(verifyAppMailboxPassword(serviceId, email, req.credentials || ''));
|
||||
if (!appPasswordError) { // validated as app
|
||||
if (addonId === 'recvmail' && (!mailbox || !mailbox.active)) return next(new ldap.NoSuchObjectError(req.dn.toString())); // recvmail requires active mailbox
|
||||
if (serviceNeedsMailbox && (!mailbox || !mailbox.active)) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
return res.end();
|
||||
}
|
||||
|
||||
if (appPasswordError && appPasswordError.reason === BoxError.INVALID_CREDENTIALS) return next(new ldap.InvalidCredentialsError(req.dn.toString()));
|
||||
if (appPasswordError && appPasswordError.reason !== BoxError.NOT_FOUND) return next(new ldap.OperationsError(appPasswordError.message));
|
||||
|
||||
// user password check requires an active mailbox for recvmail and sendmail addon
|
||||
// user password check requires an active mailbox
|
||||
if (!mailbox) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
if (!mailbox.active) return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||
|
||||
@@ -676,8 +677,9 @@ async function start() {
|
||||
gServer.search('ou=mailaliases,dc=cloudron', mailAliasSearch); // haraka
|
||||
gServer.search('ou=mailinglists,dc=cloudron', mailingListSearch); // haraka
|
||||
|
||||
gServer.bind('ou=recvmail,dc=cloudron', authenticateMailAddon); // dovecot (IMAP auth)
|
||||
gServer.bind('ou=sendmail,dc=cloudron', authenticateMailAddon); // haraka (MSA auth)
|
||||
gServer.bind('ou=imap,dc=cloudron', authenticateMail); // dovecot (IMAP auth)
|
||||
gServer.bind('ou=msa,dc=cloudron', authenticateMail); // haraka (MSA auth)
|
||||
gServer.bind('ou=sieve,dc=cloudron', authenticateMail); // dovecot (sieve auth)
|
||||
|
||||
gServer.bind('ou=sftp,dc=cloudron', authenticateSftp); // sftp
|
||||
gServer.search('ou=sftp,dc=cloudron', userSearchSftp);
|
||||
|
||||
Reference in New Issue
Block a user