DTrace rework so probes always fire
This commit is contained in:
parent
4f2dc61feb
commit
57831b56d1
|
@ -0,0 +1,197 @@
|
|||
var ldap = require('../lib/index');
|
||||
|
||||
|
||||
///--- Shared handlers
|
||||
|
||||
function authorize(req, res, next) {
|
||||
if (!req.connection.ldap.bindDN.equals('cn=root'))
|
||||
return next(new ldap.InsufficientAccessRightsError());
|
||||
|
||||
return next();
|
||||
}
|
||||
|
||||
|
||||
///--- Globals
|
||||
|
||||
var SUFFIX = 'o=smartdc';
|
||||
var db = {};
|
||||
var server = ldap.createServer();
|
||||
|
||||
|
||||
|
||||
server.bind('cn=root', function(req, res, next) {
|
||||
if (req.dn.toString() !== 'cn=root' || req.credentials !== 'secret')
|
||||
return next(new ldap.InvalidCredentialsError());
|
||||
|
||||
res.end();
|
||||
return next();
|
||||
});
|
||||
|
||||
server.add(SUFFIX, authorize, function(req, res, next) {
|
||||
var dn = req.dn.toString();
|
||||
|
||||
if (db[dn])
|
||||
return next(new ldap.EntryAlreadyExistsError(dn));
|
||||
|
||||
db[dn] = req.toObject().attributes;
|
||||
res.end();
|
||||
return next();
|
||||
});
|
||||
|
||||
server.bind(SUFFIX, function(req, res, next) {
|
||||
var dn = req.dn.toString();
|
||||
if (!db[dn])
|
||||
return next(new ldap.NoSuchObjectError(dn));
|
||||
|
||||
if (!dn[dn].userpassword)
|
||||
return next(new ldap.NoSuchAttributeError('userPassword'));
|
||||
|
||||
if (db[dn].userpassword !== req.credentials)
|
||||
return next(new ldap.InvalidCredentialsError());
|
||||
|
||||
res.end();
|
||||
return next();
|
||||
});
|
||||
|
||||
server.compare(SUFFIX, authorize, function(req, res, next) {
|
||||
var dn = req.dn.toString();
|
||||
if (!db[dn])
|
||||
return next(new ldap.NoSuchObjectError(dn));
|
||||
|
||||
if (!db[dn][req.attribute])
|
||||
return next(new ldap.NoSuchAttributeError(req.attribute));
|
||||
|
||||
var matches = false;
|
||||
var vals = db[dn][req.attribute];
|
||||
for (var i = 0; i < vals.length; i++) {
|
||||
if (vals[i] === req.value) {
|
||||
matches = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
res.end(matches);
|
||||
return next();
|
||||
});
|
||||
|
||||
server.del(SUFFIX, authorize, function(req, res, next) {
|
||||
var dn = req.dn.toString();
|
||||
if (!db[dn])
|
||||
return next(new ldap.NoSuchObjectError(dn));
|
||||
|
||||
delete db[dn];
|
||||
|
||||
res.end();
|
||||
return next();
|
||||
});
|
||||
|
||||
server.modify(SUFFIX, authorize, function(req, res, next) {
|
||||
var dn = req.dn.toString();
|
||||
if (!req.changes.length)
|
||||
return next(new ldap.ProtocolError('changes required'));
|
||||
if (!db[dn])
|
||||
return next(new ldap.NoSuchObjectError(dn));
|
||||
|
||||
var entry = db[dn];
|
||||
|
||||
for (var i = 0; i < req.changes.length; i++) {
|
||||
mod = req.changes[i].modification;
|
||||
switch (req.changes[i].operation) {
|
||||
case 'replace':
|
||||
if (!entry[mod.type])
|
||||
return next(new ldap.NoSuchAttributeError(mod.type));
|
||||
|
||||
if (!mod.vals || !mod.vals.length) {
|
||||
delete entry[mod.type];
|
||||
} else {
|
||||
entry[mod.type] = mod.vals;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'add':
|
||||
if (!entry[mod.type]) {
|
||||
entry[mod.type] = mod.vals;
|
||||
} else {
|
||||
mod.vals.forEach(function(v) {
|
||||
if (entry[mod.type].indexOf(v) === -1)
|
||||
entry[mod.type].push(v);
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
if (!entry[mod.type])
|
||||
return next(new ldap.NoSuchAttributeError(mod.type));
|
||||
|
||||
delete entry[mod.type];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
res.end();
|
||||
return next();
|
||||
});
|
||||
|
||||
server.search(SUFFIX, authorize, function(req, res, next) {
|
||||
var dn = req.dn.toString();
|
||||
if (!db[dn])
|
||||
return next(new ldap.NoSuchObjectError(dn));
|
||||
|
||||
var scopeCheck;
|
||||
|
||||
switch (req.scope) {
|
||||
case 'base':
|
||||
if (req.filter.matches(db[dn])) {
|
||||
res.send({
|
||||
dn: dn,
|
||||
attributes: db[dn]
|
||||
});
|
||||
}
|
||||
|
||||
res.end();
|
||||
return next();
|
||||
|
||||
case 'one':
|
||||
scopeCheck = function(k) {
|
||||
if (req.dn.equals(k))
|
||||
return true;
|
||||
|
||||
var parent = ldap.parseDN(k).parent();
|
||||
return (parent ? parent.equals(req.dn) : false);
|
||||
};
|
||||
break;
|
||||
|
||||
case 'sub':
|
||||
scopeCheck = function(k) {
|
||||
return (req.dn.equals(k) || req.dn.parentOf(k));
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Object.keys(db).forEach(function(key) {
|
||||
if (!scopeCheck(key))
|
||||
return;
|
||||
|
||||
if (req.filter.matches(db[key])) {
|
||||
res.send({
|
||||
dn: key,
|
||||
attributes: db[key]
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
res.end();
|
||||
return next();
|
||||
});
|
||||
|
||||
|
||||
|
||||
///--- Fire it up
|
||||
|
||||
server.listen(1389, function() {
|
||||
console.log('LDAP server up at: %s', server.url);
|
||||
});
|
|
@ -3,6 +3,8 @@
|
|||
var assert = require('assert');
|
||||
var util = require('util');
|
||||
|
||||
var dtrace = require('../dtrace');
|
||||
|
||||
var LDAPMessage = require('./result');
|
||||
var Protocol = require('../protocol');
|
||||
|
||||
|
@ -38,6 +40,21 @@ UnbindResponse.prototype.end = function(status) {
|
|||
this.log.trace('%s: unbinding!', this.connection.ldap.id);
|
||||
|
||||
this.connection.end();
|
||||
|
||||
var self = this;
|
||||
if (self._dtraceOp && self._dtraceId) {
|
||||
dtrace.fire('server-' + self._dtraceOp + '-done', function() {
|
||||
var c = self.connection || {ldap: {}};
|
||||
return [
|
||||
self._dtraceId || 0,
|
||||
(c.remoteAddress || ''),
|
||||
c.ldap.bindDN ? c.ldap.bindDN.toString() : '',
|
||||
(self.requestDN ? self.requestDN.toString() : ''),
|
||||
0,
|
||||
''
|
||||
];
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
182
lib/server.js
182
lib/server.js
|
@ -135,27 +135,7 @@ function defaultHandler(req, res, next) {
|
|||
}
|
||||
|
||||
|
||||
function defaultAbandonHandler(req, res, next) {
|
||||
assert.ok(req);
|
||||
assert.ok(res);
|
||||
assert.ok(next);
|
||||
|
||||
res.end();
|
||||
return next();
|
||||
}
|
||||
|
||||
|
||||
function defaultUnbindHandler(req, res, next) {
|
||||
assert.ok(req);
|
||||
assert.ok(res);
|
||||
assert.ok(next);
|
||||
|
||||
res.end();
|
||||
return next();
|
||||
}
|
||||
|
||||
|
||||
function defaultAnonymousBindHandler(req, res, next) {
|
||||
function defaultNoOpHandler(req, res, next) {
|
||||
assert.ok(req);
|
||||
assert.ok(res);
|
||||
assert.ok(next);
|
||||
|
@ -187,32 +167,69 @@ function noExOpHandler(req, res, next) {
|
|||
}
|
||||
|
||||
|
||||
function getArgumentsWithDTrace(args, op, cb1, cb2) {
|
||||
assert.ok(op);
|
||||
function fireDTraceProbe(req, res) {
|
||||
assert.ok(req);
|
||||
|
||||
var index = 0;
|
||||
if (typeof(args[0]) === 'object')
|
||||
index = 1;
|
||||
req._dtraceId = res._dtraceId = dtrace._nextId();
|
||||
var probeArgs = [
|
||||
req._dtraceId,
|
||||
req.connection.remoteAddress || 'localhost',
|
||||
req.connection.ldap.bindDN.toString(),
|
||||
req.dn.toString(),
|
||||
];
|
||||
|
||||
args.splice(index, 0, function(req, res, next) {
|
||||
req._dtraceId = res._dtraceId = dtrace._nextId();
|
||||
res._dtraceOp = op;
|
||||
dtrace.fire('server-' + res._dtraceOp + '-start', function() {
|
||||
return [
|
||||
res._dtraceId,
|
||||
req.connection.remoteAddress,
|
||||
req.connection.ldap.bindDN.toString(),
|
||||
req.dn.toString(),
|
||||
cb1 ? cb1(req, res) : undefined,
|
||||
cb2 ? cb2(req, res) : undefined
|
||||
];
|
||||
});
|
||||
return next();
|
||||
var op;
|
||||
switch (req.protocolOp) {
|
||||
case Protocol.LDAP_REQ_ABANDON:
|
||||
op = 'abandon';
|
||||
break;
|
||||
case Protocol.LDAP_REQ_ADD:
|
||||
op = 'add';
|
||||
probeArgs.push(req.attributes.length);
|
||||
break;
|
||||
case Protocol.LDAP_REQ_BIND:
|
||||
op = 'bind';
|
||||
break;
|
||||
case Protocol.LDAP_REQ_COMPARE:
|
||||
op = 'compare';
|
||||
probeArgs.push(req.attribute);
|
||||
probeArgs.push(req.value);
|
||||
break;
|
||||
case Protocol.LDAP_REQ_DELETE:
|
||||
op = 'delete';
|
||||
break;
|
||||
case Protocol.LDAP_REQ_EXTENSION:
|
||||
op = 'exop';
|
||||
probeArgs.push(req.name);
|
||||
probeArgs.push(req.value);
|
||||
break;
|
||||
case Protocol.LDAP_REQ_MODIFY:
|
||||
op = 'modify';
|
||||
probeArgs.push(req.changes.length);
|
||||
break;
|
||||
case Protocol.LDAP_REQ_MODRDN:
|
||||
op = 'modifydn';
|
||||
probeArgs.push(req.newRdn.toString());
|
||||
probeArgs.push((req.newSuperior ? req.newSuperior.toString() : ''));
|
||||
break;
|
||||
case Protocol.LDAP_REQ_SEARCH:
|
||||
op = 'search';
|
||||
probeArgs.push(req.scope);
|
||||
probeArgs.push(req.filter.toString());
|
||||
break;
|
||||
case Protocol.LDAP_REQ_UNBIND:
|
||||
op = 'unbind';
|
||||
break;
|
||||
}
|
||||
|
||||
res._dtraceOp = op;
|
||||
dtrace.fire('server-' + op + '-start', function() {
|
||||
return probeArgs;
|
||||
});
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///--- API
|
||||
|
||||
/**
|
||||
|
@ -338,7 +355,7 @@ function Server(options) {
|
|||
res.logId = req.logId;
|
||||
res.requestDN = req.dn;
|
||||
|
||||
var chain = self._getHandlerChain(req);
|
||||
var chain = self._getHandlerChain(req, res);
|
||||
|
||||
var i = 0;
|
||||
return function(err) {
|
||||
|
@ -468,12 +485,7 @@ module.exports = Server;
|
|||
* @throws {TypeError} on bad input
|
||||
*/
|
||||
Server.prototype.add = function(name) {
|
||||
var args = getArgumentsWithDTrace(Array.prototype.slice.call(arguments, 1),
|
||||
'add',
|
||||
function(req, res) {
|
||||
return req.attributes.length;
|
||||
});
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
return this._mount(Protocol.LDAP_REQ_ADD, name, args);
|
||||
};
|
||||
|
||||
|
@ -489,9 +501,7 @@ Server.prototype.add = function(name) {
|
|||
* @throws {TypeError} on bad input
|
||||
*/
|
||||
Server.prototype.bind = function(name) {
|
||||
var args = getArgumentsWithDTrace(Array.prototype.slice.call(arguments, 1),
|
||||
'bind');
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
return this._mount(Protocol.LDAP_REQ_BIND, name, args);
|
||||
};
|
||||
|
||||
|
@ -507,15 +517,7 @@ Server.prototype.bind = function(name) {
|
|||
* @throws {TypeError} on bad input
|
||||
*/
|
||||
Server.prototype.compare = function(name) {
|
||||
var args = getArgumentsWithDTrace(Array.prototype.slice.call(arguments, 1),
|
||||
'compare',
|
||||
function(req, res) {
|
||||
return req.attribute;
|
||||
},
|
||||
function(req, res) {
|
||||
return req.value;
|
||||
});
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
return this._mount(Protocol.LDAP_REQ_COMPARE, name, args);
|
||||
};
|
||||
|
||||
|
@ -531,9 +533,7 @@ Server.prototype.compare = function(name) {
|
|||
* @throws {TypeError} on bad input
|
||||
*/
|
||||
Server.prototype.del = function(name) {
|
||||
var args = getArgumentsWithDTrace(Array.prototype.slice.call(arguments, 1),
|
||||
'delete');
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
return this._mount(Protocol.LDAP_REQ_DELETE, name, args);
|
||||
};
|
||||
|
||||
|
@ -549,15 +549,7 @@ Server.prototype.del = function(name) {
|
|||
* @throws {TypeError} on bad input.
|
||||
*/
|
||||
Server.prototype.exop = function(name) {
|
||||
var args = getArgumentsWithDTrace(Array.prototype.slice.call(arguments, 1),
|
||||
'exop',
|
||||
function(req, res) {
|
||||
return req.name;
|
||||
},
|
||||
function(req, res) {
|
||||
return req.value;
|
||||
});
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
return this._mount(Protocol.LDAP_REQ_EXTENSION, name, args, true);
|
||||
};
|
||||
|
||||
|
@ -573,12 +565,7 @@ Server.prototype.exop = function(name) {
|
|||
* @throws {TypeError} on bad input
|
||||
*/
|
||||
Server.prototype.modify = function(name) {
|
||||
var args = getArgumentsWithDTrace(Array.prototype.slice.call(arguments, 1),
|
||||
'modify',
|
||||
function(req, res) {
|
||||
return req.changes.length;
|
||||
});
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
return this._mount(Protocol.LDAP_REQ_MODIFY, name, args);
|
||||
};
|
||||
|
||||
|
@ -594,16 +581,7 @@ Server.prototype.modify = function(name) {
|
|||
* @throws {TypeError} on bad input
|
||||
*/
|
||||
Server.prototype.modifyDN = function(name) {
|
||||
var args = getArgumentsWithDTrace(Array.prototype.slice.call(arguments, 1),
|
||||
'modifydn',
|
||||
function(req, res) {
|
||||
return req.newRdn.toString();
|
||||
},
|
||||
function(req, res) {
|
||||
return (req.newSuperior ?
|
||||
req.newSuperior.toString() : '');
|
||||
});
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
return this._mount(Protocol.LDAP_REQ_MODRDN, name, args);
|
||||
};
|
||||
|
||||
|
@ -619,15 +597,7 @@ Server.prototype.modifyDN = function(name) {
|
|||
* @throws {TypeError} on bad input
|
||||
*/
|
||||
Server.prototype.search = function(name) {
|
||||
var args = getArgumentsWithDTrace(Array.prototype.slice.call(arguments, 1),
|
||||
'search',
|
||||
function(req, res) {
|
||||
return req.scope;
|
||||
},
|
||||
function(req, res) {
|
||||
return req.filter.toString();
|
||||
});
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
return this._mount(Protocol.LDAP_REQ_SEARCH, name, args);
|
||||
};
|
||||
|
||||
|
@ -642,9 +612,7 @@ Server.prototype.search = function(name) {
|
|||
* @throws {TypeError} on bad input
|
||||
*/
|
||||
Server.prototype.unbind = function() {
|
||||
var args = getArgumentsWithDTrace(Array.prototype.slice.call(arguments, 1),
|
||||
'unbind');
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
return this._mount(Protocol.LDAP_REQ_UNBIND, 'unbind', args, true);
|
||||
};
|
||||
|
||||
|
@ -726,16 +694,18 @@ Server.prototype._getRoute = function(_dn, backend) {
|
|||
};
|
||||
|
||||
|
||||
Server.prototype._getHandlerChain = function(req) {
|
||||
Server.prototype._getHandlerChain = function(req, res) {
|
||||
assert.ok(req);
|
||||
|
||||
fireDTraceProbe(req, res);
|
||||
|
||||
// check anonymous bind
|
||||
if (req.protocolOp === Protocol.LDAP_REQ_BIND &&
|
||||
req.dn.toString() === '' &&
|
||||
req.credentials === '') {
|
||||
return {
|
||||
backend: self,
|
||||
handlers: [defaultAnonymousBindHandler]
|
||||
handlers: [defaultNoOpHandler]
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -763,7 +733,7 @@ Server.prototype._getHandlerChain = function(req) {
|
|||
return routes['unbind'][op];
|
||||
|
||||
self.log.debug('%s unbind request %j', req.logId, req.json);
|
||||
return [defaultUnbindHandler];
|
||||
return [defaultNoOpHandler];
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -773,7 +743,7 @@ Server.prototype._getHandlerChain = function(req) {
|
|||
} else if (req.protocolOp === Protocol.LDAP_REQ_ABANDON) {
|
||||
return {
|
||||
backend: self,
|
||||
handlers: [defaultAbandonHandler]
|
||||
handlers: [defaultNoOpHandler]
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -811,7 +781,7 @@ Server.prototype._mount = function(op, name, argv, notDN) {
|
|||
|
||||
if (typeof(name) !== 'string')
|
||||
throw new TypeError('name (string) required');
|
||||
if (argv.length < 1)
|
||||
if (!argv.length)
|
||||
throw new Error('at least one handler required');
|
||||
|
||||
var backend = this;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "ldapjs",
|
||||
"homepage": "http://ldapjs.org",
|
||||
"description": "LDAP client and server APIs",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/mcavage/node-ldapjs.git"
|
||||
|
|
Loading…
Reference in New Issue