Add alias and list ldap routes
This commit is contained in:
107
src/ldap.js
107
src/ldap.js
@@ -15,7 +15,8 @@ var assert = require('assert'),
|
||||
UserError = user.UserError,
|
||||
ldap = require('ldapjs'),
|
||||
mailboxdb = require('./mailboxdb.js'),
|
||||
safe = require('safetydance');
|
||||
safe = require('safetydance'),
|
||||
util = require('util');
|
||||
|
||||
var gServer = null;
|
||||
|
||||
@@ -133,24 +134,102 @@ function groupSearch(req, res, next) {
|
||||
function getMailbox(req, res, next) {
|
||||
debug('mailbox get: dn %s, scope %s, filter %s (from %s)', req.dn.toString(), req.scope, req.filter.toString(), req.connection.ldap.id);
|
||||
|
||||
if (!req.dn.rdns[0].attrs.cn) return next(new ldap.OperationsError('CN is required'));
|
||||
|
||||
mailboxes.get(
|
||||
mailboxes.getAll(function (error, result) {
|
||||
// http://www.zytrax.com/books/ldap/ape/courier.html
|
||||
// http://www.ldapadmin.org/docs/postfix.schema
|
||||
// https://wiki.zimbra.com/wiki/5.0.15_Directory_Schema
|
||||
var get = !!req.dn.rdns[0].attrs.cn;
|
||||
var func = get ? mailboxdb.getMailbox.bind(null, req.dn.rdns[0].attrs.cn) : mailboxdb.getMailboxes;
|
||||
func(function (error, result) {
|
||||
if (error) return next(new ldap.OperationsError(error.toString()));
|
||||
|
||||
result.forEach(function (entry) {
|
||||
var dn = ldap.parseDN('cn=' + entry.name + ',ou=mailboxes,dc=cloudron');
|
||||
var results = util.isArray(result) ? result : [ result ];
|
||||
|
||||
results.forEach(function (mailbox) {
|
||||
var dn = ldap.parseDN('cn=' + mailbox.name + ',ou=mailboxes,dc=cloudron');
|
||||
|
||||
// TODO: send aliases
|
||||
var obj = {
|
||||
dn: dn.toString(),
|
||||
dn: req.dn.toString(),
|
||||
attributes: {
|
||||
objectclass: ['mailbox'],
|
||||
objectcategory: 'mailbox',
|
||||
cn: entry.name,
|
||||
uid: entry.name,
|
||||
mail: entry.name + '@' + config.fqdn()
|
||||
cn: name,
|
||||
uid: mailbox.ownerId,
|
||||
mail: name + '@' + config.fqdn()
|
||||
}
|
||||
};
|
||||
|
||||
// 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)) {
|
||||
res.send(obj);
|
||||
}
|
||||
});
|
||||
|
||||
res.end();
|
||||
});
|
||||
}
|
||||
|
||||
function getMailAlias(req, res, next) {
|
||||
debug('mail alias get: dn %s, scope %s, filter %s (from %s)', req.dn.toString(), req.scope, req.filter.toString(), req.connection.ldap.id);
|
||||
|
||||
// https://wiki.debian.org/LDAP/MigrationTools/Examples
|
||||
var get = !!req.dn.rdns[0].attrs.cn;
|
||||
var func = get ? mailboxdb.getAlias.bind(null, req.dn.rdns[0].attrs.cn) : mailboxdb.getAliases;
|
||||
func(function (error, result) {
|
||||
if (error) return next(new ldap.OperationsError(error.toString()));
|
||||
|
||||
var results = util.isArray(result) ? result : [ result ];
|
||||
|
||||
results.forEach(function (alias) {
|
||||
var dn = ldap.parseDN('cn=' + alias.name + ',ou=mailaliases,dc=cloudron');
|
||||
|
||||
var obj = {
|
||||
dn: dn.toString(),
|
||||
attributes: {
|
||||
objectclass: ['nisMailAlias'],
|
||||
objectcategory: 'nisMailAlias',
|
||||
cn: alias.name,
|
||||
rfc822MailMember: alias.aliasTarget
|
||||
}
|
||||
};
|
||||
|
||||
// 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)) {
|
||||
res.send(obj);
|
||||
}
|
||||
});
|
||||
|
||||
res.end();
|
||||
});
|
||||
}
|
||||
|
||||
function getMailGroup(req, res, next) {
|
||||
debug('mailgroup get: dn %s, scope %s, filter %s (from %s)', req.dn.toString(), req.scope, req.filter.toString(), req.connection.ldap.id);
|
||||
|
||||
// https://docs.oracle.com/cd/E19455-01/806-5580/6jej518pp/index.html
|
||||
var get = !!req.dn.rdns[0].attrs.cn;
|
||||
var func = get ? mailboxdb.getGroup.bind(null, req.dn.rdns[0].attrs.cn) : mailboxdb.getGroups;
|
||||
func(function (error, result) {
|
||||
if (error) return next(new ldap.OperationsError(error.toString()));
|
||||
|
||||
var results = util.isArray(result) ? result : [ result ];
|
||||
|
||||
results.forEach(function (group) {
|
||||
var dn = ldap.parseDN('cn=' + group.name + ',ou=mailgroups,dc=cloudron');
|
||||
|
||||
var obj = {
|
||||
dn: dn.toString(),
|
||||
attributes: {
|
||||
objectclass: ['mailGroup'],
|
||||
objectcategory: 'mailGroup',
|
||||
cn: group.name,
|
||||
mail: group.name,
|
||||
mgrpRFC822MailMember: group.members
|
||||
}
|
||||
};
|
||||
|
||||
@@ -254,7 +333,11 @@ function start(callback) {
|
||||
gServer.search('ou=groups,dc=cloudron', groupSearch);
|
||||
gServer.bind('ou=users,dc=cloudron', authenticateUser, authorizeUserForApp);
|
||||
|
||||
// http://www.ietf.org/proceedings/43/I-D/draft-srivastava-ldap-mail-00.txt
|
||||
gServer.search('ou=mailboxes,dc=cloudron', getMailbox);
|
||||
gServer.search('ou=mailaliases,dc=cloudron', getMailAlias);
|
||||
gServer.search('ou=mailgroups,dc=cloudron', getMailGroup);
|
||||
|
||||
gServer.bind('ou=mailboxes,dc=cloudron', authenticateUser, authorizeUserForMailbox);
|
||||
|
||||
// this is the bind for addons (after bind, they might search and authenticate)
|
||||
|
||||
@@ -5,8 +5,14 @@ exports = module.exports = {
|
||||
del: del,
|
||||
upsertByOwner: upsertByOwner,
|
||||
get: get,
|
||||
getMailboxes: getMailboxes,
|
||||
getMailbox: getMailbox,
|
||||
getGroup: getGroup,
|
||||
getGroups: getGroups,
|
||||
getAliases: getAliases,
|
||||
setAliases: setAliases,
|
||||
getAlias: getAlias,
|
||||
getAliasesOf: getAliasesOf,
|
||||
setAliasesOf: setAliasesOf,
|
||||
getByOwnerId: getByOwnerId,
|
||||
delByOwnerId: delByOwnerId,
|
||||
|
||||
@@ -99,6 +105,53 @@ function get(name, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
function getMailbox(name, callback) {
|
||||
assert.strictEqual(typeof name, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
database.query('SELECT ' + MAILBOX_FIELDS + ' FROM mailboxes WHERE name = ? AND (ownerType = ? OR ownerType = ?)', [ name, exports.TYPE_APP, exports.TYPE_USER ], function (error, results) {
|
||||
if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error));
|
||||
if (results.length === 0) return callback(new DatabaseError(DatabaseError.NOT_FOUND));
|
||||
|
||||
callback(null, results[0]);
|
||||
});
|
||||
}
|
||||
|
||||
function getMailboxes(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
database.query('SELECT ' + MAILBOX_FIELDS + ' FROM mailboxes WHERE ownerType = ? OR ownerType = ?', [ exports.TYPE_APP, exports.TYPE_USER ], function (error, results) {
|
||||
if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error));
|
||||
|
||||
callback(null, results);
|
||||
});
|
||||
}
|
||||
|
||||
function getGroup(name, callback) {
|
||||
assert.strictEqual(typeof name, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
// FIXME: fix the query to return members
|
||||
database.query('SELECT ' + MAILBOX_FIELDS + ' FROM mailboxes WHERE name = ? AND ownerType = ?', [ name, exports.TYPE_GROUP ], function (error, results) {
|
||||
if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error));
|
||||
if (results.length === 0) return callback(new DatabaseError(DatabaseError.NOT_FOUND));
|
||||
|
||||
callback(null, results[0]);
|
||||
});
|
||||
}
|
||||
|
||||
function getGroups(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
// FIXME: fix the query to return members
|
||||
database.query('SELECT ' + MAILBOX_FIELDS + ' FROM mailboxes WHERE ownerType = ?',
|
||||
[ exports.TYPE_GROUP ], function (error, results) {
|
||||
if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error));
|
||||
|
||||
callback(null, results);
|
||||
});
|
||||
}
|
||||
|
||||
function getByOwnerId(ownerId, callback) {
|
||||
assert.strictEqual(typeof ownerId, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
@@ -111,7 +164,7 @@ function getByOwnerId(ownerId, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
function setAliases(name, aliases, ownerId, ownerType, callback) {
|
||||
function setAliasesOf(name, aliases, ownerId, ownerType, callback) {
|
||||
assert.strictEqual(typeof name, 'string');
|
||||
assert(util.isArray(aliases));
|
||||
assert.strictEqual(typeof ownerId, 'string');
|
||||
@@ -133,7 +186,7 @@ function setAliases(name, aliases, ownerId, ownerType, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
function getAliases(name, callback) {
|
||||
function getAliasesOf(name, callback) {
|
||||
assert.strictEqual(typeof name, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
@@ -144,3 +197,25 @@ function getAliases(name, callback) {
|
||||
callback(null, results);
|
||||
});
|
||||
}
|
||||
|
||||
function getAliases(callback) {
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
database.query('SELECT name FROM mailboxes WHERE aliasTarget != null ORDER BY name', function (error, results) {
|
||||
if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error));
|
||||
|
||||
callback(null, results);
|
||||
});
|
||||
}
|
||||
|
||||
function getAlias(name, callback) {
|
||||
assert.strictEqual(typeof name, 'string');
|
||||
assert.strictEqual(typeof callback, 'function');
|
||||
|
||||
database.query('SELECT name FROM mailboxes WHERE name = ? AND aliasTarget != null', [ name ], function (error, results) {
|
||||
if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error));
|
||||
if (results.length === 0) return callback(new DatabaseError(DatabaseError.NOT_FOUND));
|
||||
|
||||
callback(null, results[0]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1205,14 +1205,14 @@ describe('database', function () {
|
||||
});
|
||||
|
||||
it('can set alias', function (done) {
|
||||
mailboxdb.setAliases('support', [ 'support2', 'help' ], 'support', 'user', function (error) {
|
||||
mailboxdb.setAliasesOf('support', [ 'support2', 'help' ], 'support', 'user', function (error) {
|
||||
expect(error).to.be(null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('can get alias', function (done) {
|
||||
mailboxdb.getAliases('support', function (error, results) {
|
||||
mailboxdb.getAliasesOf('support', function (error, results) {
|
||||
expect(error).to.be(null);
|
||||
expect(results.length).to.be(2);
|
||||
expect(results[0]).to.be('help');
|
||||
@@ -1222,7 +1222,7 @@ describe('database', function () {
|
||||
});
|
||||
|
||||
it('unset aliases', function (done) {
|
||||
mailboxdb.setAliases('support', [ ], 'support', 'user', function (error) {
|
||||
mailboxdb.setAliasesOf('support', [ ], 'support', 'user', function (error) {
|
||||
expect(error).to.be(null);
|
||||
|
||||
mailboxdb.getAliases('support', function (error, results) {
|
||||
|
||||
@@ -582,7 +582,7 @@ function setAliases(userId, aliases, callback) {
|
||||
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UserError(UserError.NOT_FOUND));
|
||||
if (error) return callback(new UserError(UserError.INTERNAL_ERROR, error));
|
||||
|
||||
mailboxdb.setAliases(user.username, aliases, userId, mailboxdb.TYPE_USER, function (error) {
|
||||
mailboxdb.setAliasesOf(user.username, aliases, userId, mailboxdb.TYPE_USER, function (error) {
|
||||
if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(new UserError(UserError.ALREADY_EXISTS, error.message));
|
||||
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UserError(UserError.NOT_FOUND));
|
||||
if (error) return callback(new UserError(UserError.INTERNAL_ERROR, error));
|
||||
@@ -601,7 +601,7 @@ function getAliases(userId, callback) {
|
||||
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UserError(UserError.NOT_FOUND));
|
||||
if (error) return callback(new UserError(UserError.INTERNAL_ERROR, error));
|
||||
|
||||
mailboxdb.getAliases(user.username, function (error, aliases) {
|
||||
mailboxdb.getAliasesOf(user.username, function (error, aliases) {
|
||||
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UserError(UserError.NOT_FOUND));
|
||||
if (error) return callback(new UserError(UserError.INTERNAL_ERROR, error));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user