Documentation and makefile
This commit is contained in:
parent
e87550ff57
commit
17d2d4e5cb
|
@ -1,3 +1,5 @@
|
||||||
node_modules
|
node_modules
|
||||||
*.log
|
*.log
|
||||||
*.ldif
|
*.ldif
|
||||||
|
*.tar*
|
||||||
|
docs/pkg
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
NAME=ldapjs
|
||||||
|
|
||||||
|
ifeq ($(VERSION), "")
|
||||||
|
@echo "Use gmake"
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
SRC := $(shell pwd)
|
||||||
|
TAR = tar
|
||||||
|
UNAME := $(shell uname)
|
||||||
|
ifeq ($(UNAME), SunOS)
|
||||||
|
TAR = gtar
|
||||||
|
endif
|
||||||
|
|
||||||
|
HAVE_GJSLINT := $(shell which gjslint >/dev/null && echo yes || echo no)
|
||||||
|
NPM := npm_config_tar=$(TAR) npm
|
||||||
|
|
||||||
|
RESTDOWN = ./node_modules/.restdown/bin/restdown
|
||||||
|
RESTDOWN_VERSION=1.2.11
|
||||||
|
DOCPKGDIR = ./docs/pkg
|
||||||
|
|
||||||
|
.PHONY: dep lint test doc clean all
|
||||||
|
|
||||||
|
all:: test doc
|
||||||
|
|
||||||
|
node_modules/.ldapjs.npm.installed:
|
||||||
|
$(NPM) install --dev
|
||||||
|
if [[ ! -d node_modules/.restdown ]]; then \
|
||||||
|
git clone git://github.com/trentm/restdown.git node_modules/.restdown; \
|
||||||
|
else \
|
||||||
|
(cd node_modules/.restdown && git fetch origin); \
|
||||||
|
fi
|
||||||
|
@(cd ./node_modules/.restdown && git checkout $(RESTDOWN_VERSION))
|
||||||
|
@touch ./node_modules/.ldapjs.npm.installed
|
||||||
|
|
||||||
|
dep: ./node_modules/.ldapjs.npm.installed
|
||||||
|
|
||||||
|
gjslint:
|
||||||
|
gjslint --nojsdoc -r lib -r tst
|
||||||
|
|
||||||
|
ifeq ($(HAVE_GJSLINT), yes)
|
||||||
|
lint: gjslint
|
||||||
|
else
|
||||||
|
lint:
|
||||||
|
@echo "* * *"
|
||||||
|
@echo "* Warning: Cannot lint with gjslint. Install it from:"
|
||||||
|
@echo "* http://code.google.com/closure/utilities/docs/linter_howto.html"
|
||||||
|
@echo "* * *"
|
||||||
|
endif
|
||||||
|
|
||||||
|
doc: dep
|
||||||
|
@rm -rf ${DOCPKGDIR}
|
||||||
|
@mkdir -p ${DOCPKGDIR}
|
||||||
|
${RESTDOWN} -m ${DOCPKGDIR} -D mediaroot=media ./docs/guide.md
|
||||||
|
rm docs/*.json
|
||||||
|
mv docs/*.html ${DOCPKGDIR}
|
||||||
|
sed -i '' -e 's|docs/public/media|media|g' ${DOCPKGDIR}/*.html
|
||||||
|
(cd ${DOCPKGDIR} && $(TAR) -czf ${SRC}/${NAME}-docs-`git log -1 --pretty='format:%h'`.tar.gz *)
|
||||||
|
|
||||||
|
|
||||||
|
test: dep lint
|
||||||
|
$(NPM) test
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -fr ${DOCPKGDIR} node_modules *.log
|
350
docs/guide.md
350
docs/guide.md
|
@ -28,12 +28,12 @@ basically breaks down as follows:
|
||||||
|
|
||||||
It might be helpful to visualize that:
|
It might be helpful to visualize that:
|
||||||
|
|
||||||
o=example
|
o=example
|
||||||
/ \
|
/ \
|
||||||
ou=users ou=groups
|
ou=users ou=groups
|
||||||
/ | | \
|
/ | | \
|
||||||
cn=john cn=jane cn=dudes cn=dudettes
|
cn=john cn=jane cn=dudes cn=dudettes
|
||||||
/
|
/
|
||||||
keyid=foo
|
keyid=foo
|
||||||
|
|
||||||
|
|
||||||
|
@ -187,8 +187,8 @@ Blah blah, let's try running the ldap client again, first with a bad password:
|
||||||
$ ldapsearch -H ldap://localhost:1389 -x -D cn=root -w foo -b "o=myhost" objectclass=*
|
$ ldapsearch -H ldap://localhost:1389 -x -D cn=root -w foo -b "o=myhost" objectclass=*
|
||||||
|
|
||||||
ldap_bind: Invalid credentials (49)
|
ldap_bind: Invalid credentials (49)
|
||||||
matched DN: cn=root
|
matched DN: cn=root
|
||||||
additional info: Invalid Credentials
|
additional info: Invalid Credentials
|
||||||
|
|
||||||
And again with the correct one:
|
And again with the correct one:
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ authorization handler that we'll use in all our subsequent routes:
|
||||||
|
|
||||||
function authorize(req, res, next) {
|
function authorize(req, res, next) {
|
||||||
if (!req.connection.ldap.bindDN.equals('cn=root'))
|
if (!req.connection.ldap.bindDN.equals('cn=root'))
|
||||||
return next(new ldap.InsufficientAccessRightsError());
|
return next(new ldap.InsufficientAccessRightsError());
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
@ -249,35 +249,35 @@ First, let's make a handler that just loads the "user database" for us in a
|
||||||
|
|
||||||
function loadPasswdFile(req, res, next) {
|
function loadPasswdFile(req, res, next) {
|
||||||
fs.readFile('/etc/passwd', 'utf8', function(err, data) {
|
fs.readFile('/etc/passwd', 'utf8', function(err, data) {
|
||||||
if (err)
|
if (err)
|
||||||
return next(new ldap.OperationsError(err.message));
|
return next(new ldap.OperationsError(err.message));
|
||||||
|
|
||||||
req.users = {};
|
req.users = {};
|
||||||
|
|
||||||
var lines = data.split('\n');
|
var lines = data.split('\n');
|
||||||
for (var i = 0; i < lines.length; i++) {
|
for (var i = 0; i < lines.length; i++) {
|
||||||
if (!lines[i] || /^#/.test(lines[i]))
|
if (!lines[i] || /^#/.test(lines[i]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var record = lines[i].split(':');
|
var record = lines[i].split(':');
|
||||||
if (!record || !record.length)
|
if (!record || !record.length)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
req.users[record[0]] = {
|
req.users[record[0]] = {
|
||||||
dn: 'cn=' + record[0] + ', ou=users, o=myhost',
|
dn: 'cn=' + record[0] + ', ou=users, o=myhost',
|
||||||
attributes: {
|
attributes: {
|
||||||
cn: record[0],
|
cn: record[0],
|
||||||
uid: record[2],
|
uid: record[2],
|
||||||
gid: record[3],
|
gid: record[3],
|
||||||
description: record[4],
|
description: record[4],
|
||||||
homedirectory: record[5],
|
homedirectory: record[5],
|
||||||
shell: record[6] || '',
|
shell: record[6] || '',
|
||||||
objectclass: 'unixUser'
|
objectclass: 'unixUser'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,8 +289,8 @@ handler to process that:
|
||||||
|
|
||||||
server.search('o=myhost', pre, function(req, res, next) {
|
server.search('o=myhost', pre, function(req, res, next) {
|
||||||
Object.keys(req.users).forEach(function(k) {
|
Object.keys(req.users).forEach(function(k) {
|
||||||
if (req.filter.matches(req.users[k].attributes))
|
if (req.filter.matches(req.users[k].attributes))
|
||||||
res.send(req.users[k]);
|
res.send(req.users[k]);
|
||||||
});
|
});
|
||||||
|
|
||||||
res.end();
|
res.end();
|
||||||
|
@ -357,13 +357,13 @@ of attributes. So that's why we did this:
|
||||||
var entry = {
|
var entry = {
|
||||||
dn: 'cn=' + record[0] + ', ou=users, o=myhost',
|
dn: 'cn=' + record[0] + ', ou=users, o=myhost',
|
||||||
attributes: {
|
attributes: {
|
||||||
cn: record[0],
|
cn: record[0],
|
||||||
uid: record[2],
|
uid: record[2],
|
||||||
gid: record[3],
|
gid: record[3],
|
||||||
description: record[4],
|
description: record[4],
|
||||||
homedirectory: record[5],
|
homedirectory: record[5],
|
||||||
shell: record[6] || '',
|
shell: record[6] || '',
|
||||||
objectclass: 'unixUser'
|
objectclass: 'unixUser'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -398,36 +398,36 @@ the following code in as another handler (you'll need a
|
||||||
|
|
||||||
server.add('ou=users, o=myhost', pre, function(req, res, next) {
|
server.add('ou=users, o=myhost', pre, function(req, res, next) {
|
||||||
if (!req.dn.rdns[0].cn)
|
if (!req.dn.rdns[0].cn)
|
||||||
return next(new ldap.ConstraintViolationError('cn required'));
|
return next(new ldap.ConstraintViolationError('cn required'));
|
||||||
|
|
||||||
if (req.users[req.dn.rdns[0].cn])
|
if (req.users[req.dn.rdns[0].cn])
|
||||||
return next(new ldap.EntryAlreadyExistsError(req.dn.toString()));
|
return next(new ldap.EntryAlreadyExistsError(req.dn.toString()));
|
||||||
|
|
||||||
var entry = req.toObject().attributes;
|
var entry = req.toObject().attributes;
|
||||||
|
|
||||||
if (entry.objectclass.indexOf('unixUser') === -1)
|
if (entry.objectclass.indexOf('unixUser') === -1)
|
||||||
return next(new ldap.ConstraintViolation('entry must be a unixUser'));
|
return next(new ldap.ConstraintViolation('entry must be a unixUser'));
|
||||||
|
|
||||||
var opts = ['-m'];
|
var opts = ['-m'];
|
||||||
if (entry.description) {
|
if (entry.description) {
|
||||||
opts.push('-c');
|
opts.push('-c');
|
||||||
opts.push(entry.description[0]);
|
opts.push(entry.description[0]);
|
||||||
}
|
}
|
||||||
if (entry.homedirectory) {
|
if (entry.homedirectory) {
|
||||||
opts.push('-d');
|
opts.push('-d');
|
||||||
opts.push(entry.homedirectory[0]);
|
opts.push(entry.homedirectory[0]);
|
||||||
}
|
}
|
||||||
if (entry.gid) {
|
if (entry.gid) {
|
||||||
opts.push('-g');
|
opts.push('-g');
|
||||||
opts.push(entry.gid[0]);
|
opts.push(entry.gid[0]);
|
||||||
}
|
}
|
||||||
if (entry.shell) {
|
if (entry.shell) {
|
||||||
opts.push('-s');
|
opts.push('-s');
|
||||||
opts.push(entry.shell[0]);
|
opts.push(entry.shell[0]);
|
||||||
}
|
}
|
||||||
if (entry.uid) {
|
if (entry.uid) {
|
||||||
opts.push('-u');
|
opts.push('-u');
|
||||||
opts.push(entry.uid[0]);
|
opts.push(entry.uid[0]);
|
||||||
}
|
}
|
||||||
opts.push(entry.cn[0]);
|
opts.push(entry.cn[0]);
|
||||||
var useradd = spawn('useradd', opts);
|
var useradd = spawn('useradd', opts);
|
||||||
|
@ -435,22 +435,22 @@ the following code in as another handler (you'll need a
|
||||||
var messages = [];
|
var messages = [];
|
||||||
|
|
||||||
useradd.stdout.on('data', function(data) {
|
useradd.stdout.on('data', function(data) {
|
||||||
messages.push(data.toString());
|
messages.push(data.toString());
|
||||||
});
|
});
|
||||||
useradd.stderr.on('data', function(data) {
|
useradd.stderr.on('data', function(data) {
|
||||||
messages.push(data.toString());
|
messages.push(data.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
useradd.on('exit', function(code) {
|
useradd.on('exit', function(code) {
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
var msg = '' + code;
|
var msg = '' + code;
|
||||||
if (messages.length)
|
if (messages.length)
|
||||||
msg += ': ' + messages.join();
|
msg += ': ' + messages.join();
|
||||||
return next(new ldap.OperationsError(msg));
|
return next(new ldap.OperationsError(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
res.end();
|
res.end();
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -485,15 +485,15 @@ As before, here's a breakdown of the code:
|
||||||
|
|
||||||
server.add('ou=users, o=myhost', pre, function(req, res, next) {
|
server.add('ou=users, o=myhost', pre, function(req, res, next) {
|
||||||
if (!req.dn.rdns[0].cn)
|
if (!req.dn.rdns[0].cn)
|
||||||
return next(new ldap.ConstraintViolationError('cn required'));
|
return next(new ldap.ConstraintViolationError('cn required'));
|
||||||
|
|
||||||
if (req.users[req.dn.rdns[0].cn])
|
if (req.users[req.dn.rdns[0].cn])
|
||||||
return next(new ldap.EntryAlreadyExistsError(req.dn.toString()));
|
return next(new ldap.EntryAlreadyExistsError(req.dn.toString()));
|
||||||
|
|
||||||
var entry = req.toObject().attributes;
|
var entry = req.toObject().attributes;
|
||||||
|
|
||||||
if (entry.objectclass.indexOf('unixUser') === -1)
|
if (entry.objectclass.indexOf('unixUser') === -1)
|
||||||
return next(new ldap.ConstraintViolation('entry must be a unixUser'));
|
return next(new ldap.ConstraintViolation('entry must be a unixUser'));
|
||||||
|
|
||||||
Here's a few new things:
|
Here's a few new things:
|
||||||
|
|
||||||
|
@ -530,37 +530,37 @@ Go ahead and add the following code into your source file:
|
||||||
|
|
||||||
server.modify('ou=users, o=myhost', pre, function(req, res, next) {
|
server.modify('ou=users, o=myhost', pre, function(req, res, next) {
|
||||||
if (!req.dn.rdns[0].cn || !req.users[req.dn.rdns[0].cn])
|
if (!req.dn.rdns[0].cn || !req.users[req.dn.rdns[0].cn])
|
||||||
return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||||
|
|
||||||
if (!req.changes.length)
|
if (!req.changes.length)
|
||||||
return next(new ldap.ProtocolError('changes required'));
|
return next(new ldap.ProtocolError('changes required'));
|
||||||
|
|
||||||
var user = req.users[req.dn.rdns[0].cn].attributes;
|
var user = req.users[req.dn.rdns[0].cn].attributes;
|
||||||
var mod;
|
var mod;
|
||||||
|
|
||||||
for (var i = 0; i < req.changes.length; i++) {
|
for (var i = 0; i < req.changes.length; i++) {
|
||||||
mod = req.changes[i].modification;
|
mod = req.changes[i].modification;
|
||||||
switch (req.changes[i].operation) {
|
switch (req.changes[i].operation) {
|
||||||
case 'replace':
|
case 'replace':
|
||||||
if (mod.type !== 'userpassword' || !mod.vals || !mod.vals.length)
|
if (mod.type !== 'userpassword' || !mod.vals || !mod.vals.length)
|
||||||
return next(new ldap.UnwillingToPerformError('only password updates ' +
|
return next(new ldap.UnwillingToPerformError('only password updates ' +
|
||||||
'allowed'));
|
'allowed'));
|
||||||
break;
|
break;
|
||||||
case 'add':
|
case 'add':
|
||||||
case 'delete':
|
case 'delete':
|
||||||
return next(new ldap.UnwillingToPerformError('only replace allowed'));
|
return next(new ldap.UnwillingToPerformError('only replace allowed'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var passwd = spawn('chpasswd', ['-c', 'MD5']);
|
var passwd = spawn('chpasswd', ['-c', 'MD5']);
|
||||||
passwd.stdin.end(user.cn + ':' + mod.vals[0], 'utf8');
|
passwd.stdin.end(user.cn + ':' + mod.vals[0], 'utf8');
|
||||||
|
|
||||||
passwd.on('exit', function(code) {
|
passwd.on('exit', function(code) {
|
||||||
if (code !== 0)
|
if (code !== 0)
|
||||||
return next(new ldap.OperationsError(code));
|
return next(new ldap.OperationsError(code));
|
||||||
|
|
||||||
res.end();
|
res.end();
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -592,28 +592,28 @@ delete it :). Go ahead and add the following code into your server:
|
||||||
|
|
||||||
server.del('ou=users, o=myhost', pre, function(req, res, next) {
|
server.del('ou=users, o=myhost', pre, function(req, res, next) {
|
||||||
if (!req.dn.rdns[0].cn || !req.users[req.dn.rdns[0].cn])
|
if (!req.dn.rdns[0].cn || !req.users[req.dn.rdns[0].cn])
|
||||||
return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||||
|
|
||||||
var userdel = spawn('userdel', ['-f', req.dn.rdns[0].cn]);
|
var userdel = spawn('userdel', ['-f', req.dn.rdns[0].cn]);
|
||||||
|
|
||||||
var messages = [];
|
var messages = [];
|
||||||
userdel.stdout.on('data', function(data) {
|
userdel.stdout.on('data', function(data) {
|
||||||
messages.push(data.toString());
|
messages.push(data.toString());
|
||||||
});
|
});
|
||||||
userdel.stderr.on('data', function(data) {
|
userdel.stderr.on('data', function(data) {
|
||||||
messages.push(data.toString());
|
messages.push(data.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
userdel.on('exit', function(code) {
|
userdel.on('exit', function(code) {
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
var msg = '' + code;
|
var msg = '' + code;
|
||||||
if (messages.length)
|
if (messages.length)
|
||||||
msg += ': ' + messages.join();
|
msg += ': ' + messages.join();
|
||||||
return next(new ldap.OperationsError(msg));
|
return next(new ldap.OperationsError(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
res.end();
|
res.end();
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -638,7 +638,7 @@ the complete implementation for what we went through above:
|
||||||
|
|
||||||
function authorize(req, res, next) {
|
function authorize(req, res, next) {
|
||||||
if (!req.connection.ldap.bindDN.equals('cn=root'))
|
if (!req.connection.ldap.bindDN.equals('cn=root'))
|
||||||
return next(new ldap.InsufficientAccessRightsError());
|
return next(new ldap.InsufficientAccessRightsError());
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
@ -646,35 +646,35 @@ the complete implementation for what we went through above:
|
||||||
|
|
||||||
function loadPasswdFile(req, res, next) {
|
function loadPasswdFile(req, res, next) {
|
||||||
fs.readFile('/etc/passwd', 'utf8', function(err, data) {
|
fs.readFile('/etc/passwd', 'utf8', function(err, data) {
|
||||||
if (err)
|
if (err)
|
||||||
return next(new ldap.OperationsError(err.message));
|
return next(new ldap.OperationsError(err.message));
|
||||||
|
|
||||||
req.users = {};
|
req.users = {};
|
||||||
|
|
||||||
var lines = data.split('\n');
|
var lines = data.split('\n');
|
||||||
for (var i = 0; i < lines.length; i++) {
|
for (var i = 0; i < lines.length; i++) {
|
||||||
if (!lines[i] || /^#/.test(lines[i]))
|
if (!lines[i] || /^#/.test(lines[i]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var record = lines[i].split(':');
|
var record = lines[i].split(':');
|
||||||
if (!record || !record.length)
|
if (!record || !record.length)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
req.users[record[0]] = {
|
req.users[record[0]] = {
|
||||||
dn: 'cn=' + record[0] + ', ou=users, o=myhost',
|
dn: 'cn=' + record[0] + ', ou=users, o=myhost',
|
||||||
attributes: {
|
attributes: {
|
||||||
cn: record[0],
|
cn: record[0],
|
||||||
uid: record[2],
|
uid: record[2],
|
||||||
gid: record[3],
|
gid: record[3],
|
||||||
description: record[4],
|
description: record[4],
|
||||||
homedirectory: record[5],
|
homedirectory: record[5],
|
||||||
shell: record[6] || '',
|
shell: record[6] || '',
|
||||||
objectclass: 'unixUser'
|
objectclass: 'unixUser'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,7 +689,7 @@ the complete implementation for what we went through above:
|
||||||
|
|
||||||
server.bind('cn=root', function(req, res, next) {
|
server.bind('cn=root', function(req, res, next) {
|
||||||
if (req.dn.toString() !== 'cn=root' || req.credentials !== 'secret')
|
if (req.dn.toString() !== 'cn=root' || req.credentials !== 'secret')
|
||||||
return next(new ldap.InvalidCredentialsError());
|
return next(new ldap.InvalidCredentialsError());
|
||||||
|
|
||||||
res.end();
|
res.end();
|
||||||
return next();
|
return next();
|
||||||
|
@ -698,36 +698,36 @@ the complete implementation for what we went through above:
|
||||||
|
|
||||||
server.add('ou=users, o=myhost', pre, function(req, res, next) {
|
server.add('ou=users, o=myhost', pre, function(req, res, next) {
|
||||||
if (!req.dn.rdns[0].cn)
|
if (!req.dn.rdns[0].cn)
|
||||||
return next(new ldap.ConstraintViolationError('cn required'));
|
return next(new ldap.ConstraintViolationError('cn required'));
|
||||||
|
|
||||||
if (req.users[req.dn.rdns[0].cn])
|
if (req.users[req.dn.rdns[0].cn])
|
||||||
return next(new ldap.EntryAlreadyExistsError(req.dn.toString()));
|
return next(new ldap.EntryAlreadyExistsError(req.dn.toString()));
|
||||||
|
|
||||||
var entry = req.toObject().attributes;
|
var entry = req.toObject().attributes;
|
||||||
|
|
||||||
if (entry.objectclass.indexOf('unixUser') === -1)
|
if (entry.objectclass.indexOf('unixUser') === -1)
|
||||||
return next(new ldap.ConstraintViolation('entry must be a unixUser'));
|
return next(new ldap.ConstraintViolation('entry must be a unixUser'));
|
||||||
|
|
||||||
var opts = ['-m'];
|
var opts = ['-m'];
|
||||||
if (entry.description) {
|
if (entry.description) {
|
||||||
opts.push('-c');
|
opts.push('-c');
|
||||||
opts.push(entry.description[0]);
|
opts.push(entry.description[0]);
|
||||||
}
|
}
|
||||||
if (entry.homedirectory) {
|
if (entry.homedirectory) {
|
||||||
opts.push('-d');
|
opts.push('-d');
|
||||||
opts.push(entry.homedirectory[0]);
|
opts.push(entry.homedirectory[0]);
|
||||||
}
|
}
|
||||||
if (entry.gid) {
|
if (entry.gid) {
|
||||||
opts.push('-g');
|
opts.push('-g');
|
||||||
opts.push(entry.gid[0]);
|
opts.push(entry.gid[0]);
|
||||||
}
|
}
|
||||||
if (entry.shell) {
|
if (entry.shell) {
|
||||||
opts.push('-s');
|
opts.push('-s');
|
||||||
opts.push(entry.shell[0]);
|
opts.push(entry.shell[0]);
|
||||||
}
|
}
|
||||||
if (entry.uid) {
|
if (entry.uid) {
|
||||||
opts.push('-u');
|
opts.push('-u');
|
||||||
opts.push(entry.uid[0]);
|
opts.push(entry.uid[0]);
|
||||||
}
|
}
|
||||||
opts.push(entry.cn[0]);
|
opts.push(entry.cn[0]);
|
||||||
var useradd = spawn('useradd', opts);
|
var useradd = spawn('useradd', opts);
|
||||||
|
@ -735,95 +735,95 @@ the complete implementation for what we went through above:
|
||||||
var messages = [];
|
var messages = [];
|
||||||
|
|
||||||
useradd.stdout.on('data', function(data) {
|
useradd.stdout.on('data', function(data) {
|
||||||
messages.push(data.toString());
|
messages.push(data.toString());
|
||||||
});
|
});
|
||||||
useradd.stderr.on('data', function(data) {
|
useradd.stderr.on('data', function(data) {
|
||||||
messages.push(data.toString());
|
messages.push(data.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
useradd.on('exit', function(code) {
|
useradd.on('exit', function(code) {
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
var msg = '' + code;
|
var msg = '' + code;
|
||||||
if (messages.length)
|
if (messages.length)
|
||||||
msg += ': ' + messages.join();
|
msg += ': ' + messages.join();
|
||||||
return next(new ldap.OperationsError(msg));
|
return next(new ldap.OperationsError(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
res.end();
|
res.end();
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
server.modify('ou=users, o=myhost', pre, function(req, res, next) {
|
server.modify('ou=users, o=myhost', pre, function(req, res, next) {
|
||||||
if (!req.dn.rdns[0].cn || !req.users[req.dn.rdns[0].cn])
|
if (!req.dn.rdns[0].cn || !req.users[req.dn.rdns[0].cn])
|
||||||
return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||||
|
|
||||||
if (!req.changes.length)
|
if (!req.changes.length)
|
||||||
return next(new ldap.ProtocolError('changes required'));
|
return next(new ldap.ProtocolError('changes required'));
|
||||||
|
|
||||||
var user = req.users[req.dn.rdns[0].cn].attributes;
|
var user = req.users[req.dn.rdns[0].cn].attributes;
|
||||||
var mod;
|
var mod;
|
||||||
|
|
||||||
for (var i = 0; i < req.changes.length; i++) {
|
for (var i = 0; i < req.changes.length; i++) {
|
||||||
mod = req.changes[i].modification;
|
mod = req.changes[i].modification;
|
||||||
switch (req.changes[i].operation) {
|
switch (req.changes[i].operation) {
|
||||||
case 'replace':
|
case 'replace':
|
||||||
if (mod.type !== 'userpassword' || !mod.vals || !mod.vals.length)
|
if (mod.type !== 'userpassword' || !mod.vals || !mod.vals.length)
|
||||||
return next(new ldap.UnwillingToPerformError('only password updates ' +
|
return next(new ldap.UnwillingToPerformError('only password updates ' +
|
||||||
'allowed'));
|
'allowed'));
|
||||||
break;
|
break;
|
||||||
case 'add':
|
case 'add':
|
||||||
case 'delete':
|
case 'delete':
|
||||||
return next(new ldap.UnwillingToPerformError('only replace allowed'));
|
return next(new ldap.UnwillingToPerformError('only replace allowed'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var passwd = spawn('chpasswd', ['-c', 'MD5']);
|
var passwd = spawn('chpasswd', ['-c', 'MD5']);
|
||||||
passwd.stdin.end(user.cn + ':' + mod.vals[0], 'utf8');
|
passwd.stdin.end(user.cn + ':' + mod.vals[0], 'utf8');
|
||||||
|
|
||||||
passwd.on('exit', function(code) {
|
passwd.on('exit', function(code) {
|
||||||
if (code !== 0)
|
if (code !== 0)
|
||||||
return next(new ldap.OperationsError('' + code));
|
return next(new ldap.OperationsError('' + code));
|
||||||
|
|
||||||
res.end();
|
res.end();
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
server.del('ou=users, o=myhost', pre, function(req, res, next) {
|
server.del('ou=users, o=myhost', pre, function(req, res, next) {
|
||||||
if (!req.dn.rdns[0].cn || !req.users[req.dn.rdns[0].cn])
|
if (!req.dn.rdns[0].cn || !req.users[req.dn.rdns[0].cn])
|
||||||
return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
return next(new ldap.NoSuchObjectError(req.dn.toString()));
|
||||||
|
|
||||||
var userdel = spawn('userdel', ['-f', req.dn.rdns[0].cn]);
|
var userdel = spawn('userdel', ['-f', req.dn.rdns[0].cn]);
|
||||||
|
|
||||||
var messages = [];
|
var messages = [];
|
||||||
userdel.stdout.on('data', function(data) {
|
userdel.stdout.on('data', function(data) {
|
||||||
messages.push(data.toString());
|
messages.push(data.toString());
|
||||||
});
|
});
|
||||||
userdel.stderr.on('data', function(data) {
|
userdel.stderr.on('data', function(data) {
|
||||||
messages.push(data.toString());
|
messages.push(data.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
userdel.on('exit', function(code) {
|
userdel.on('exit', function(code) {
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
var msg = '' + code;
|
var msg = '' + code;
|
||||||
if (messages.length)
|
if (messages.length)
|
||||||
msg += ': ' + messages.join();
|
msg += ': ' + messages.join();
|
||||||
return next(new ldap.OperationsError(msg));
|
return next(new ldap.OperationsError(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
res.end();
|
res.end();
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
server.search('o=myhost', pre, function(req, res, next) {
|
server.search('o=myhost', pre, function(req, res, next) {
|
||||||
Object.keys(req.users).forEach(function(k) {
|
Object.keys(req.users).forEach(function(k) {
|
||||||
if (req.filter.matches(req.users[k].attributes))
|
if (req.filter.matches(req.users[k].attributes))
|
||||||
res.send(req.users[k]);
|
res.send(req.users[k]);
|
||||||
});
|
});
|
||||||
|
|
||||||
res.end();
|
res.end();
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
"node-uuid": "~1.2.0"
|
"node-uuid": "~1.2.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"pretest": "which gjslint; if [[ \"$?\" = 0 ]] ; then gjslint --nojsdoc -r lib -r tst; else echo \"Missing gjslint. Skipping lint\"; fi",
|
|
||||||
"test": "./node_modules/.bin/tap ./tst"
|
"test": "./node_modules/.bin/tap ./tst"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue