Initial DTrace prototype
This commit is contained in:
parent
679b4e5c37
commit
695f2e4367
|
@ -0,0 +1 @@
|
||||||
|
mark@bluesnoop.local.63414
|
|
@ -0,0 +1,18 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
|
var ldap = require('../../lib/index');
|
||||||
|
|
||||||
|
var client = ldap.createClient({
|
||||||
|
url: 'ldap://localhost:1389'
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var finished = 0;
|
||||||
|
var ITERATIONS = 1024;
|
||||||
|
for (var i = 0; i < ITERATIONS; i++) {
|
||||||
|
client.bind('cn=root', 'secret', function(err) {
|
||||||
|
assert.ifError(err);
|
||||||
|
if (++finished === ITERATIONS)
|
||||||
|
client.unbind();
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
ldapjs*::bind:entry
|
||||||
|
{
|
||||||
|
/*self->start = timestamp;*/
|
||||||
|
}
|
||||||
|
ldapjs*:::return
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
/self->start/
|
||||||
|
@ = quantize(timestamp - self->start);
|
||||||
|
self->start = 0;"
|
||||||
|
*/
|
||||||
|
}
|
|
@ -0,0 +1,201 @@
|
||||||
|
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=joyent';
|
||||||
|
var db = {};
|
||||||
|
|
||||||
|
//ldap.log4js.setLevel('Trace');
|
||||||
|
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);
|
||||||
|
});
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
|
||||||
|
|
||||||
|
var dtrace = require('dtrace-provider');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///--- Globals
|
||||||
|
|
||||||
|
var SERVER_PROVIDER;
|
||||||
|
|
||||||
|
/* Args:
|
||||||
|
* 0 -> remoteIP
|
||||||
|
* 1 -> bindDN
|
||||||
|
* 2 -> req.dn
|
||||||
|
* 3..5 -> op specific
|
||||||
|
*/
|
||||||
|
var SERVER_PROBES = {
|
||||||
|
|
||||||
|
add: ['char "*', 'char *', 'char *'],
|
||||||
|
bind: ['char "*', 'char *', 'char *'],
|
||||||
|
unbind: ['char "*', 'char *', 'char *'],
|
||||||
|
connection: ['char *']
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
///--- API
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
ServerProbes: SERVER_PROBES,
|
||||||
|
|
||||||
|
|
||||||
|
serverProvider: function() {
|
||||||
|
if (!SERVER_PROVIDER) {
|
||||||
|
SERVER_PROVIDER = dtrace.createDTraceProvider('ldapjs');
|
||||||
|
|
||||||
|
Object.keys(SERVER_PROBES).forEach(function(p) {
|
||||||
|
var args = SERVER_PROBES[p].splice(0);
|
||||||
|
args.unshift(p);
|
||||||
|
console.log('%j', args);
|
||||||
|
dtrace.DTraceProvider.prototype.addProbe.apply(SERVER_PROVIDER, args);
|
||||||
|
});
|
||||||
|
|
||||||
|
SERVER_PROVIDER.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
return SERVER_PROVIDER;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -10,6 +10,7 @@ var asn1 = require('asn1');
|
||||||
var sprintf = require('sprintf').sprintf;
|
var sprintf = require('sprintf').sprintf;
|
||||||
|
|
||||||
var dn = require('./dn');
|
var dn = require('./dn');
|
||||||
|
var dtrace = require('./dtrace');
|
||||||
var errors = require('./errors');
|
var errors = require('./errors');
|
||||||
var Protocol = require('./protocol');
|
var Protocol = require('./protocol');
|
||||||
var logStub = require('./log_stub');
|
var logStub = require('./log_stub');
|
||||||
|
@ -215,6 +216,7 @@ function Server(options) {
|
||||||
|
|
||||||
EventEmitter.call(this, options);
|
EventEmitter.call(this, options);
|
||||||
|
|
||||||
|
this.dtrace = dtrace.serverProvider();
|
||||||
this.log = options.log4js.getLogger('Server');
|
this.log = options.log4js.getLogger('Server');
|
||||||
var log = this.log;
|
var log = this.log;
|
||||||
|
|
||||||
|
@ -263,6 +265,7 @@ function Server(options) {
|
||||||
setupConnection(c);
|
setupConnection(c);
|
||||||
if (log.isTraceEnabled())
|
if (log.isTraceEnabled())
|
||||||
log.trace('new connection from %s', c.ldap.id);
|
log.trace('new connection from %s', c.ldap.id);
|
||||||
|
self.dtrace.fire('connection', function() { return [c.remoteAddress]; });
|
||||||
|
|
||||||
c.parser = new Parser({
|
c.parser = new Parser({
|
||||||
log4js: options.log4js
|
log4js: options.log4js
|
||||||
|
@ -387,9 +390,17 @@ module.exports = Server;
|
||||||
* @throws {TypeError} on bad input
|
* @throws {TypeError} on bad input
|
||||||
*/
|
*/
|
||||||
Server.prototype.add = function(name) {
|
Server.prototype.add = function(name) {
|
||||||
return this._mount(Protocol.LDAP_REQ_ADD,
|
var self = this;
|
||||||
name,
|
|
||||||
Array.prototype.slice.call(arguments, 1));
|
var args = Array.prototype.slice.call(arguments, 1);
|
||||||
|
args.unshift(function(req, res, next) {
|
||||||
|
self.dtrace.fire('add', function() {
|
||||||
|
return [c.remoteAddress, c.ldap.bindDN.toString(), c.dn.toString()];
|
||||||
|
});
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
|
||||||
|
return this._mount(Protocol.LDAP_REQ_ADD, name, args);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -404,9 +415,18 @@ Server.prototype.add = function(name) {
|
||||||
* @throws {TypeError} on bad input
|
* @throws {TypeError} on bad input
|
||||||
*/
|
*/
|
||||||
Server.prototype.bind = function(name) {
|
Server.prototype.bind = function(name) {
|
||||||
return this._mount(Protocol.LDAP_REQ_BIND,
|
var self = this;
|
||||||
name,
|
|
||||||
Array.prototype.slice.call(arguments, 1));
|
var args = Array.prototype.slice.call(arguments, 1);
|
||||||
|
args.unshift(function(req, res, next) {
|
||||||
|
self.dtrace.fire('bind', function() {
|
||||||
|
return [c.remoteAddress, c.ldap.bindDN.toString(), c.dn.toString()];
|
||||||
|
});
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
|
||||||
|
return this._mount(Protocol.LDAP_REQ_BIND, name, args);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -523,6 +543,16 @@ Server.prototype.search = function(name) {
|
||||||
* @throws {TypeError} on bad input
|
* @throws {TypeError} on bad input
|
||||||
*/
|
*/
|
||||||
Server.prototype.unbind = function() {
|
Server.prototype.unbind = function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var args = Array.prototype.slice.call(arguments, 1);
|
||||||
|
args.unshift(function(req, res, next) {
|
||||||
|
self.dtrace.fire('unbind', function() {
|
||||||
|
return [c.remoteAddress, c.ldap.bindDN.toString(), c.dn.toString()];
|
||||||
|
});
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
|
||||||
return this._mount(Protocol.LDAP_REQ_UNBIND,
|
return this._mount(Protocol.LDAP_REQ_UNBIND,
|
||||||
'unbind',
|
'unbind',
|
||||||
Array.prototype.slice.call(arguments, 0),
|
Array.prototype.slice.call(arguments, 0),
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asn1": "~0.1.5",
|
"asn1": "~0.1.5",
|
||||||
"buffertools": "~1.0.3",
|
"buffertools": "~1.0.3",
|
||||||
|
"dtrace-provider": "~0.0.2",
|
||||||
"sprintf": "~0.1.1"
|
"sprintf": "~0.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
Loading…
Reference in New Issue