ldap: mailbox routes now require the cn to be fully qualified

This commit is contained in:
Girish Ramakrishnan
2018-01-18 18:14:31 -08:00
parent 614f13ffd0
commit 0f47dcfae6
2 changed files with 103 additions and 63 deletions
+26 -22
View File
@@ -258,14 +258,11 @@ function mailboxSearch(req, res, next) {
if (!req.dn.rdns[0].attrs.cn) return next(new ldap.NoSuchObjectError(req.dn.toString()));
var name = req.dn.rdns[0].attrs.cn.value.toLowerCase();
// allow login via email
var parts = name.split('@');
if (parts[1] === config.fqdn()) {
name = parts[0];
}
var email = req.dn.rdns[0].attrs.cn.value.toLowerCase();
var parts = email.split('@');
if (parts.length !== 2) return next(new ldap.NoSuchObjectError(req.dn.toString()));
mailboxdb.getMailbox(name, config.fqdn(), function (error, mailbox) {
mailboxdb.getMailbox(parts[0], parts[1], function (error, mailbox) {
if (error && error.reason === DatabaseError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString()));
if (error) return next(new ldap.OperationsError(error.toString()));
@@ -276,7 +273,7 @@ function mailboxSearch(req, res, next) {
objectcategory: 'mailbox',
cn: mailbox.name,
uid: mailbox.name,
mail: mailbox.name + '@' + config.fqdn(),
mail: mailbox.name + '@' + mailbox.domain,
ownerType: mailbox.ownerType
}
};
@@ -298,7 +295,11 @@ function mailAliasSearch(req, res, next) {
if (!req.dn.rdns[0].attrs.cn) return next(new ldap.NoSuchObjectError(req.dn.toString()));
mailboxdb.getAlias(req.dn.rdns[0].attrs.cn.value.toLowerCase(), config.fqdn(), function (error, alias) {
var email = req.dn.rdns[0].attrs.cn.value.toLowerCase();
var parts = email.split('@');
if (parts.length !== 2) return next(new ldap.NoSuchObjectError(req.dn.toString()));
mailboxdb.getAlias(parts[0], parts[1], function (error, alias) {
if (error && error.reason === DatabaseError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString()));
if (error) return next(new ldap.OperationsError(error.toString()));
@@ -331,7 +332,11 @@ function mailingListSearch(req, res, next) {
if (!req.dn.rdns[0].attrs.cn) return next(new ldap.NoSuchObjectError(req.dn.toString()));
mailboxdb.getGroup(req.dn.rdns[0].attrs.cn.value.toLowerCase(), config.fqdn(), function (error, group) {
var email = req.dn.rdns[0].attrs.cn.value.toLowerCase();
var parts = email.split('@');
if (parts.length !== 2) return next(new ldap.NoSuchObjectError(req.dn.toString()));
mailboxdb.getGroup(parts[0], parts[1], function (error, group) {
if (error && error.reason === DatabaseError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString()));
if (error) return next(new ldap.OperationsError(error.toString()));
@@ -342,7 +347,7 @@ function mailingListSearch(req, res, next) {
objectclass: ['mailGroup'],
objectcategory: 'mailGroup',
cn: group.name,
mail: group.name + '@' + config.fqdn(),
mail: group.name + '@' + group.domain,
mgrpRFC822MailMember: group.members
}
};
@@ -411,15 +416,11 @@ function authorizeUserForApp(req, res, next) {
function authenticateMailbox(req, res, next) {
if (!req.dn.rdns[0].attrs.cn) return next(new ldap.NoSuchObjectError(req.dn.toString()));
var name = req.dn.rdns[0].attrs.cn.value.toLowerCase();
var email = req.dn.rdns[0].attrs.cn.value.toLowerCase();
var parts = email.split('@');
if (parts.length !== 2) return next(new ldap.NoSuchObjectError(req.dn.toString()));
// allow login via email
var parts = name.split('@');
if (parts[1] === config.fqdn()) {
name = parts[0];
}
mailboxdb.getMailbox(name, config.fqdn(), function (error, mailbox) {
mailboxdb.getMailbox(parts[0], parts[1], function (error, mailbox) {
if (error && error.reason === DatabaseError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString()));
if (error) return next(new ldap.OperationsError(error.message));
@@ -438,9 +439,12 @@ function authenticateMailbox(req, res, next) {
return res.end();
});
} else if (mailbox.ownerType === mailboxdb.TYPE_USER) {
authenticateUser(req, res, function (error) {
if (error) return next(error);
eventlog.add(eventlog.ACTION_USER_LOGIN, { authType: 'ldap', mailboxId: name }, { userId: req.user.username });
user.verifyWithEmail(email, req.credentials || '', function (error, user) {
if (error && error.reason === UserError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString()));
if (error && error.reason === UserError.WRONG_PASSWORD) return next(new ldap.InvalidCredentialsError(req.dn.toString()));
if (error) return next(new ldap.OperationsError(error.message));
eventlog.add(eventlog.ACTION_USER_LOGIN, { authType: 'ldap', mailboxId: email }, { userId: user.username });
res.end();
});
} else {
+77 -41
View File
@@ -729,8 +729,8 @@ describe('Ldap', function () {
}
describe('search mailbox', function () {
it('get specific mailbox', function (done) {
ldapSearch('cn=' + USER_0.username + ',ou=mailboxes,dc=cloudron', 'objectclass=mailbox', function (error, entries) {
it('get specific mailbox by email', function (done) {
ldapSearch('cn=' + USER_0.username + '@example.com,ou=mailboxes,dc=cloudron', 'objectclass=mailbox', function (error, entries) {
if (error) return done(error);
expect(entries.length).to.equal(1);
expect(entries[0].cn).to.equal(USER_0.username.toLowerCase());
@@ -738,24 +738,22 @@ describe('Ldap', function () {
});
});
it('get specific mailbox by email', function (done) {
ldapSearch('cn=' + USER_0.username + '@' + config.fqdn() + ',ou=mailboxes,dc=cloudron', 'objectclass=mailbox', function (error, entries) {
if (error) return done(error);
expect(entries.length).to.equal(1);
expect(entries[0].cn).to.equal(USER_0.username.toLowerCase());
it('cannot get mailbox with just name', function (done) {
ldapSearch('cn=' + USER_0.username + ',ou=mailboxes,dc=cloudron', 'objectclass=mailbox', function (error, entries) {
expect(error).to.be.a(ldap.NoSuchObjectError);
done();
});
});
it('cannot get alias as a mailbox', function (done) {
ldapSearch('cn=' + USER_0_ALIAS + ',ou=mailboxes,dc=cloudron', 'objectclass=mailbox', function (error) {
ldapSearch('cn=' + USER_0_ALIAS + '@example.com,ou=mailboxes,dc=cloudron', 'objectclass=mailbox', function (error) {
expect(error).to.be.a(ldap.NoSuchObjectError);
done();
});
});
it('non-existent mailbox', function (done) {
ldapSearch('cn=random,ou=mailboxes,dc=cloudron', 'objectclass=mailbox', function (error) {
ldapSearch('cn=random@example.com,ou=mailboxes,dc=cloudron', 'objectclass=mailbox', function (error) {
expect(error).to.be.a(ldap.NoSuchObjectError);
done();
});
@@ -764,7 +762,7 @@ describe('Ldap', function () {
describe('search aliases', function () {
it('get specific alias', function (done) {
ldapSearch('cn=' + USER_0_ALIAS + ',ou=mailaliases,dc=cloudron', 'objectclass=nismailalias', function (error, entries) {
ldapSearch('cn=' + USER_0_ALIAS + '@example.com,ou=mailaliases,dc=cloudron', 'objectclass=nismailalias', function (error, entries) {
if (error) return done(error);
expect(entries.length).to.equal(1);
expect(entries[0].cn).to.equal('asterix');
@@ -774,14 +772,14 @@ describe('Ldap', function () {
});
it('cannot get mailbox as alias', function (done) {
ldapSearch('cn=' + USER_0.username + ',ou=mailaliases,dc=cloudron', 'objectclass=nismailalias', function (error) {
ldapSearch('cn=' + USER_0.username + '@example.com,ou=mailaliases,dc=cloudron', 'objectclass=nismailalias', function (error) {
expect(error).to.be.a(ldap.NoSuchObjectError);
done();
});
});
it('non-existent alias', function (done) {
ldapSearch('cn=random,ou=mailaliases,dc=cloudron', 'objectclass=mailbox', function (error) {
ldapSearch('cn=random@example.com,ou=mailaliases,dc=cloudron', 'objectclass=mailbox', function (error) {
expect(error).to.be.a(ldap.NoSuchObjectError);
done();
});
@@ -790,7 +788,7 @@ describe('Ldap', function () {
describe('search groups', function () {
it('get specific alias', function (done) {
ldapSearch('cn=' + USER_0_ALIAS + ',ou=mailaliases,dc=cloudron', 'objectclass=nismailalias', function (error, entries) {
ldapSearch('cn=' + USER_0_ALIAS + '@example.com,ou=mailaliases,dc=cloudron', 'objectclass=nismailalias', function (error, entries) {
if (error) return done(error);
expect(entries.length).to.equal(1);
expect(entries[0].cn).to.equal('asterix');
@@ -800,7 +798,7 @@ describe('Ldap', function () {
});
it('non-existent alias', function (done) {
ldapSearch('cn=random,ou=mailaliases,dc=cloudron', 'objectclass=mailbox', function (error) {
ldapSearch('cn=random@example.com,ou=mailaliases,dc=cloudron', 'objectclass=mailbox', function (error) {
expect(error).to.be.a(ldap.NoSuchObjectError);
done();
});
@@ -809,7 +807,7 @@ describe('Ldap', function () {
describe('search mailing list', function () {
it('get specific list', function (done) {
ldapSearch('cn=developers,ou=mailinglists,dc=cloudron', 'objectclass=mailGroup', function (error, entries) {
ldapSearch('cn=developers@example.com,ou=mailinglists,dc=cloudron', 'objectclass=mailGroup', function (error, entries) {
if (error) return done(error);
expect(entries.length).to.equal(1);
expect(entries[0].cn).to.equal('developers');
@@ -819,7 +817,7 @@ describe('Ldap', function () {
});
it('non-existent list', function (done) {
ldapSearch('cn=random,ou=mailinglists,dc=cloudron', 'objectclass=mailGroup', function (error) {
ldapSearch('cn=random@example.com,ou=mailinglists,dc=cloudron', 'objectclass=mailGroup', function (error) {
expect(error).to.be.a(ldap.NoSuchObjectError);
done();
});
@@ -827,32 +825,32 @@ describe('Ldap', function () {
});
describe('user sendmail bind', function () {
it('does not allow with invalid password', function (done) {
it('email disabled - cannot find domain email', function (done) {
var client = ldap.createClient({ url: 'ldap://127.0.0.1:' + config.get('ldapPort') });
client.bind('cn=' + USER_0.username + ',ou=sendmail,dc=cloudron', USER_0.password + 'nope', function (error) {
expect(error).to.be.a(ldap.InvalidCredentialsError);
client.bind('cn=' + USER_0.username + '@example.com,ou=sendmail,dc=cloudron', USER_0.password + 'nope', function (error) {
expect(error).to.be.a(ldap.NoSuchObjectError);
client.unbind(done);
});
});
it('allows with valid password', function (done) {
it('email disabled - cannot find reset email', function (done) {
var client = ldap.createClient({ url: 'ldap://127.0.0.1:' + config.get('ldapPort') });
client.bind('cn=' + USER_0.username + ',ou=sendmail,dc=cloudron', USER_0.password, function (error) {
client.unbind();
done(error);
client.bind('cn=' + USER_0.email + ',ou=sendmail,dc=cloudron', USER_0.password + 'nope', function (error) {
expect(error).to.be.a(ldap.NoSuchObjectError);
client.unbind(done);
});
});
it('allows with valid email', function (done) {
it('email enabled - allows with valid email', function (done) {
// user settingsdb instead of settings, to not trigger further events
settingsdb.set(settings.MAIL_CONFIG_KEY, JSON.stringify({ enabled: true }), function (error) {
expect(error).not.to.be.ok();
var client = ldap.createClient({ url: 'ldap://127.0.0.1:' + config.get('ldapPort') });
client.bind('cn=' + USER_0.username + '@' + config.fqdn() + ',ou=sendmail,dc=cloudron', USER_0.password, function (error) {
client.bind('cn=' + USER_0.username + '@example.com,ou=sendmail,dc=cloudron', USER_0.password, function (error) {
expect(error).not.to.be.ok();
client.unbind();
@@ -861,13 +859,35 @@ describe('Ldap', function () {
});
});
});
it('email enabled - does not allow with invalid password', function (done) {
// user settingsdb instead of settings, to not trigger further events
settingsdb.set(settings.MAIL_CONFIG_KEY, JSON.stringify({ enabled: true }), function (error) {
expect(error).not.to.be.ok();
var client = ldap.createClient({ url: 'ldap://127.0.0.1:' + config.get('ldapPort') });
client.bind('cn=' + USER_0.username + '@example.com,ou=sendmail,dc=cloudron', USER_0.password + 'nope', function (error) {
expect(error).to.be.a(ldap.InvalidCredentialsError);
client.unbind();
settingsdb.set(settings.MAIL_CONFIG_KEY, JSON.stringify({ enabled: false }), done);
});
});
});
});
describe('app sendmail bind', function () {
// these tests should work even when email is disabled
before(function (done) {
settingsdb.set(settings.MAIL_CONFIG_KEY, JSON.stringify({ enabled: false }), done);
});
it('does not allow with invalid app', function (done) {
var client = ldap.createClient({ url: 'ldap://127.0.0.1:' + config.get('ldapPort') });
client.bind('cn=hacker.app,ou=sendmail,dc=cloudron', 'nope', function (error) {
client.bind('cn=hacker.app@example.com,ou=sendmail,dc=cloudron', 'nope', function (error) {
expect(error).to.be.a(ldap.NoSuchObjectError);
client.unbind(done);
});
@@ -876,7 +896,7 @@ describe('Ldap', function () {
it('does not allow with invalid password', function (done) {
var client = ldap.createClient({ url: 'ldap://127.0.0.1:' + config.get('ldapPort') });
client.bind('cn=' + APP_0.location + '.app,ou=sendmail,dc=cloudron', 'nope', function (error) {
client.bind('cn=' + APP_0.location + '.app@example.com,ou=sendmail,dc=cloudron', 'nope', function (error) {
expect(error).to.be.a(ldap.InvalidCredentialsError);
client.unbind(done);
});
@@ -885,7 +905,7 @@ describe('Ldap', function () {
it('allows with valid password', function (done) {
var client = ldap.createClient({ url: 'ldap://127.0.0.1:' + config.get('ldapPort') });
client.bind('cn=' + APP_0.location + '.app,ou=sendmail,dc=cloudron', 'sendmailpassword', function (error) {
client.bind('cn=' + APP_0.location + '.app@example.com,ou=sendmail,dc=cloudron', 'sendmailpassword', function (error) {
client.unbind();
done(error);
});
@@ -893,33 +913,32 @@ describe('Ldap', function () {
});
describe('user recvmail bind', function () {
it('does not allow with invalid password', function (done) {
it('email disabled - cannot find domain email', function (done) {
var client = ldap.createClient({ url: 'ldap://127.0.0.1:' + config.get('ldapPort') });
client.bind('cn=' + USER_0.username + ',ou=recvmail,dc=cloudron', USER_0.password + 'nope', function (error) {
expect(error).to.be.a(ldap.InvalidCredentialsError);
client.bind('cn=' + USER_0.username + '@example.com,ou=recvmail,dc=cloudron', USER_0.password + 'nope', function (error) {
expect(error).to.be.a(ldap.NoSuchObjectError);
client.unbind(done);
});
});
it('allows with valid password', function (done) {
it('email disabled - cannot find reset email', function (done) {
var client = ldap.createClient({ url: 'ldap://127.0.0.1:' + config.get('ldapPort') });
client.bind('cn=' + USER_0.username + ',ou=recvmail,dc=cloudron', USER_0.password, function (error) {
client.unbind();
done(error);
client.bind('cn=' + USER_0.email + ',ou=recvmail,dc=cloudron', USER_0.password + 'nope', function (error) {
expect(error).to.be.a(ldap.NoSuchObjectError);
client.unbind(done);
});
});
it('allows with valid email', function (done) {
it('email enabled - allows with valid email', function (done) {
// user settingsdb instead of settings, to not trigger further events
settingsdb.set(settings.MAIL_CONFIG_KEY, JSON.stringify({ enabled: true }), function (error) {
expect(error).not.to.be.ok();
var client = ldap.createClient({ url: 'ldap://127.0.0.1:' + config.get('ldapPort') });
client.bind('cn=' + USER_0.username + '@' + config.fqdn() + ',ou=recvmail,dc=cloudron', USER_0.password, function (error) {
client.bind('cn=' + USER_0.username + '@example.com,ou=recvmail,dc=cloudron', USER_0.password, function (error) {
expect(error).not.to.be.ok();
client.unbind();
@@ -928,13 +947,30 @@ describe('Ldap', function () {
});
});
});
it('email enabled - does not allow with invalid password', function (done) {
// user settingsdb instead of settings, to not trigger further events
settingsdb.set(settings.MAIL_CONFIG_KEY, JSON.stringify({ enabled: true }), function (error) {
expect(error).not.to.be.ok();
var client = ldap.createClient({ url: 'ldap://127.0.0.1:' + config.get('ldapPort') });
client.bind('cn=' + USER_0.username + '@example.com,ou=recvmail,dc=cloudron', USER_0.password + 'nope', function (error) {
expect(error).to.be.a(ldap.InvalidCredentialsError);
client.unbind();
settingsdb.set(settings.MAIL_CONFIG_KEY, JSON.stringify({ enabled: false }), done);
});
});
});
});
describe('app recvmail bind', function () {
it('does not allow with invalid app', function (done) {
var client = ldap.createClient({ url: 'ldap://127.0.0.1:' + config.get('ldapPort') });
client.bind('cn=hacker.app,ou=recvmail,dc=cloudron', 'nope', function (error) {
client.bind('cn=hacker.app@example.com,ou=recvmail,dc=cloudron', 'nope', function (error) {
expect(error).to.be.a(ldap.NoSuchObjectError);
client.unbind(done);
});
@@ -943,7 +979,7 @@ describe('Ldap', function () {
it('does not allow with invalid password', function (done) {
var client = ldap.createClient({ url: 'ldap://127.0.0.1:' + config.get('ldapPort') });
client.bind('cn=' + APP_0.location + '.app,ou=recvmail,dc=cloudron', 'nope', function (error) {
client.bind('cn=' + APP_0.location + '.app@example.com,ou=recvmail,dc=cloudron', 'nope', function (error) {
expect(error).to.be.a(ldap.InvalidCredentialsError);
client.unbind(done);
});
@@ -952,7 +988,7 @@ describe('Ldap', function () {
it('allows with valid password', function (done) {
var client = ldap.createClient({ url: 'ldap://127.0.0.1:' + config.get('ldapPort') });
client.bind('cn=' + APP_0.location + '.app,ou=recvmail,dc=cloudron', 'recvmailpassword', function (error) {
client.bind('cn=' + APP_0.location + '.app@example.com,ou=recvmail,dc=cloudron', 'recvmailpassword', function (error) {
client.unbind();
done(error);