docs for dns, errors, filters and server, and minor fixes found along the way
This commit is contained in:
parent
7198c0a516
commit
7859f34b8a
4
Makefile
4
Makefile
|
@ -53,8 +53,12 @@ doc: dep
|
|||
@rm -rf ${DOCPKGDIR}
|
||||
@mkdir -p ${DOCPKGDIR}
|
||||
${RESTDOWN} -m ${DOCPKGDIR} -D mediaroot=media ./docs/client.md
|
||||
${RESTDOWN} -m ${DOCPKGDIR} -D mediaroot=media ./docs/dn.md
|
||||
${RESTDOWN} -m ${DOCPKGDIR} -D mediaroot=media ./docs/errors.md
|
||||
${RESTDOWN} -m ${DOCPKGDIR} -D mediaroot=media ./docs/examples.md
|
||||
${RESTDOWN} -m ${DOCPKGDIR} -D mediaroot=media ./docs/filters.md
|
||||
${RESTDOWN} -m ${DOCPKGDIR} -D mediaroot=media ./docs/guide.md
|
||||
${RESTDOWN} -m ${DOCPKGDIR} -D mediaroot=media ./docs/server.md
|
||||
rm docs/*.json
|
||||
mv docs/*.html ${DOCPKGDIR}
|
||||
(cd ${DOCPKGDIR} && $(TAR) -czf ${SRC}/${NAME}-docs-`git log -1 --pretty='format:%h'`.tar.gz *)
|
||||
|
|
|
@ -14,7 +14,7 @@ LDAP, so if you're not, hit the [guide](http://ldapjs.org/guide.html) first.
|
|||
|
||||
# Create a client
|
||||
|
||||
The code to create a new client liiks like:
|
||||
The code to create a new client looks like:
|
||||
|
||||
var client = ldap.createClient({
|
||||
url: 'ldap://127.0.0.1:1389'
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
---
|
||||
title: ldapjs
|
||||
brand: spartan
|
||||
markdown2extras: wiki-tables
|
||||
logo-color: green
|
||||
logo-font-family: google:Aldrich, Verdana, sans-serif
|
||||
header-font-family: google:Aldrich, Verdana, sans-serif
|
||||
---
|
||||
|
||||
# Overview
|
||||
|
||||
This documents the ldapjs DN API; this assumes that you are familiar with
|
||||
LDAP, so if you're not, hit the [guide](http://ldapjs.org/guide.html) first.
|
||||
|
||||
DNs are LDAP distinguished names, and are composed of a set of RDNs (relative
|
||||
distinguished names). [RFC2253](http://www.ietf.org/rfc/rfc2253.txt) has the
|
||||
complete specification, but basically an RDN is an attribute value assertion
|
||||
with `=` as the seperator, like: `cn=foo` where 'cn' is 'commonName' and 'foo'
|
||||
is the value. You can have compound RDNs by using the `+` character:
|
||||
`cn=foo+sn=bar`. As stated above, DNs are a set of RDNs, typically separated
|
||||
with the `,` character, like: `cn=foo, ou=people, o=example`. This uniquely
|
||||
identifies an entry in the tree, and is read "bottom up".
|
||||
|
||||
# parseDN(dnString)
|
||||
|
||||
The `parseDN` API converts a string representation of a DN into an ldapjs DN
|
||||
object; in most cases this will be handled for you under the covers of the
|
||||
ldapjs framework, but if you need it, it's there.
|
||||
|
||||
var parseDN = require('ldapjs').parseDN;
|
||||
|
||||
var dn = parseDN('cn=foo+sn=bar, ou=people, o=example');
|
||||
console.log(dn.toString());
|
||||
|
||||
# DN
|
||||
|
||||
The DN object is largely what you'll be interacting with, since all the server
|
||||
APIs are setup to give you a DN object.
|
||||
|
||||
## childOf(dn)
|
||||
|
||||
Returns a boolean indicating whether 'this' is a child of the passed in dn. The
|
||||
`dn` argument can be either a string or a DN.
|
||||
|
||||
server.add('o=example', function(req, res, next) {
|
||||
if (req.dn.childOf('ou=people, o=example')) {
|
||||
...
|
||||
} else {
|
||||
...
|
||||
}
|
||||
});
|
||||
|
||||
## parentOf(dn)
|
||||
|
||||
The inverse of `childOf`; returns a boolean on whether or not `this` is a parent
|
||||
of the passed in dn. Like `childOf`, can take either a string or a DN.
|
||||
|
||||
server.add('o=example', function(req, res, next) {
|
||||
var dn = parseDN('ou=people, o=example');
|
||||
if (dn.parentOf(req.dn)) {
|
||||
...
|
||||
} else {
|
||||
...
|
||||
}
|
||||
});
|
||||
|
||||
## equals(dn)
|
||||
|
||||
Returns a boolean indicating whether `this` is equivalent to the passed in `dn`
|
||||
argument. `dn` can be a string or a DN.
|
||||
|
||||
server.add('o=example', function(req, res, next) {
|
||||
if (req.dn.equals('cn=foo, ou=people, o=example')) {
|
||||
...
|
||||
} else {
|
||||
...
|
||||
}
|
||||
});
|
||||
|
||||
## parent()
|
||||
|
||||
Returns a DN object that is the direct parent of `this`. If there is no parent
|
||||
this can return `null` (e.g. `parseDN('o=example').parent()` will return null).
|
||||
|
||||
## toString()
|
||||
|
||||
Returns the string representation of `this`.
|
||||
|
||||
server.add('o=example', function(req, res, next) {
|
||||
console.log(req.dn.toString());
|
||||
});
|
|
@ -0,0 +1,93 @@
|
|||
---
|
||||
title: ldapjs
|
||||
brand: spartan
|
||||
markdown2extras: wiki-tables
|
||||
logo-color: green
|
||||
logo-font-family: google:Aldrich, Verdana, sans-serif
|
||||
header-font-family: google:Aldrich, Verdana, sans-serif
|
||||
---
|
||||
|
||||
# Overview
|
||||
|
||||
This documents the ldapjs Errors API; this assumes that you are familiar with
|
||||
LDAP, so if you're not, hit the [guide](http://ldapjs.org/guide.html) first.
|
||||
|
||||
All errors in the ldapjs framework extend from an abstract error type called
|
||||
`LDAPError`. In addition to the properties listed below, all errors will have
|
||||
a `stack` property correctly set.
|
||||
|
||||
In general, you'll be using the errors in ldapjs like:
|
||||
|
||||
var ldap = require('ldapjs');
|
||||
|
||||
var db = {};
|
||||
|
||||
server.add('o=example', function(req, res, next) {
|
||||
var parent = req.dn.parent();
|
||||
if (parent) {
|
||||
if (!db[parent.toString()])
|
||||
return next(new ldap.NoSuchObjectError(parent.toString()));
|
||||
}
|
||||
if (db[req.dn.toString()])
|
||||
return next(new ldap.EntryAlreadyExistsError(req.dn.toString()));
|
||||
|
||||
...
|
||||
});
|
||||
|
||||
I.e., if you just pass them into the `next()` handler, ldapjs will automatically
|
||||
return the appropriate LDAP error message, and stop the handler chain.
|
||||
|
||||
All errors will have the following properties:
|
||||
|
||||
## code
|
||||
|
||||
Returns the LDAP status code associated with this error.
|
||||
|
||||
## name
|
||||
|
||||
The name of this error.
|
||||
|
||||
## message
|
||||
|
||||
The message that will be returned to the client.
|
||||
|
||||
# Complete list of LDAPError subclasses
|
||||
|
||||
* OperationsError
|
||||
* ProtocolError
|
||||
* TimeLimitExceededError
|
||||
* SizeLimitExceededError
|
||||
* CompareFalseError
|
||||
* CompareTrueError
|
||||
* AuthMethodNotSupportedError
|
||||
* StrongAuthRequiredError
|
||||
* ReferralError
|
||||
* AdminLimitExceededError
|
||||
* UnavailableCriticalExtensionError
|
||||
* ConfidentialityRequiredError
|
||||
* SaslBindInProgressError
|
||||
* NoSuchAttributeError
|
||||
* UndefinedAttributeTypeError
|
||||
* InappropriateMatchingError
|
||||
* ConstraintViolationError
|
||||
* AttributeOrValueExistsError
|
||||
* InvalidAttriubteSyntaxError
|
||||
* NoSuchObjectError
|
||||
* AliasProblemError
|
||||
* InvalidDnSyntaxError
|
||||
* AliasDerefProblemError
|
||||
* InappropriateAuthenticationError
|
||||
* InvalidCredentialsError
|
||||
* InsufficientAccessRightsError
|
||||
* BusyError
|
||||
* UnavailableError
|
||||
* UnwillingToPerformError
|
||||
* LoopDetectError
|
||||
* NamingViolationError
|
||||
* ObjectclassViolationError
|
||||
* NotAllowedOnNonLeafError
|
||||
* NotAllowedOnRdnError
|
||||
* EntryAlreadyExistsError
|
||||
* ObjectclassModsProhibitedError
|
||||
* AffectsMultipleDsasError
|
||||
* OtherError
|
140
docs/examples.md
140
docs/examples.md
|
@ -16,7 +16,7 @@ header-font-family: google:Aldrich, Verdana, sans-serif
|
|||
|
||||
function authorize(req, res, next) {
|
||||
if (!req.connection.ldap.bindDN.equals('cn=root'))
|
||||
return next(new ldap.InsufficientAccessRightsError());
|
||||
return next(new ldap.InsufficientAccessRightsError());
|
||||
|
||||
return next();
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ header-font-family: google:Aldrich, Verdana, sans-serif
|
|||
|
||||
server.bind('cn=root', function(req, res, next) {
|
||||
if (req.dn.toString() !== 'cn=root' || req.credentials !== 'secret')
|
||||
return next(new ldap.InvalidCredentialsError());
|
||||
return next(new ldap.InvalidCredentialsError());
|
||||
|
||||
res.end();
|
||||
return next();
|
||||
|
@ -42,7 +42,7 @@ header-font-family: google:Aldrich, Verdana, sans-serif
|
|||
var dn = req.dn.toString();
|
||||
|
||||
if (db[dn])
|
||||
return next(new ldap.EntryAlreadyExistsError(dn));
|
||||
return next(new ldap.EntryAlreadyExistsError(dn));
|
||||
|
||||
db[dn] = req.toObject().attributes;
|
||||
res.end();
|
||||
|
@ -52,13 +52,13 @@ header-font-family: google:Aldrich, Verdana, sans-serif
|
|||
server.bind(SUFFIX, function(req, res, next) {
|
||||
var dn = req.dn.toString();
|
||||
if (!db[dn])
|
||||
return next(new ldap.NoSuchObjectError(dn));
|
||||
return next(new ldap.NoSuchObjectError(dn));
|
||||
|
||||
if (!dn[dn].userpassword)
|
||||
return next(new ldap.NoSuchAttributeError('userPassword'));
|
||||
return next(new ldap.NoSuchAttributeError('userPassword'));
|
||||
|
||||
if (db[dn].userpassword !== req.credentials)
|
||||
return next(new ldap.InvalidCredentialsError());
|
||||
return next(new ldap.InvalidCredentialsError());
|
||||
|
||||
res.end();
|
||||
return next();
|
||||
|
@ -67,18 +67,18 @@ header-font-family: google:Aldrich, Verdana, sans-serif
|
|||
server.compare(SUFFIX, authorize, function(req, res, next) {
|
||||
var dn = req.dn.toString();
|
||||
if (!db[dn])
|
||||
return next(new ldap.NoSuchObjectError(dn));
|
||||
return next(new ldap.NoSuchObjectError(dn));
|
||||
|
||||
if (!db[dn][req.attribute])
|
||||
return next(new ldap.NoSuchAttributeError(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;
|
||||
}
|
||||
if (vals[i] === req.value) {
|
||||
matches = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
res.end(matches);
|
||||
|
@ -88,7 +88,7 @@ header-font-family: google:Aldrich, Verdana, sans-serif
|
|||
server.del(SUFFIX, authorize, function(req, res, next) {
|
||||
var dn = req.dn.toString();
|
||||
if (!db[dn])
|
||||
return next(new ldap.NoSuchObjectError(dn));
|
||||
return next(new ldap.NoSuchObjectError(dn));
|
||||
|
||||
delete db[dn];
|
||||
|
||||
|
@ -99,47 +99,47 @@ header-font-family: google:Aldrich, Verdana, sans-serif
|
|||
server.modify(SUFFIX, authorize, function(req, res, next) {
|
||||
var dn = req.dn.toString();
|
||||
if (!req.changes.length)
|
||||
return next(new ldap.ProtocolError('changes required'));
|
||||
return next(new ldap.ProtocolError('changes required'));
|
||||
if (!db[dn])
|
||||
return next(new ldap.NoSuchObjectError(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));
|
||||
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;
|
||||
}
|
||||
if (!mod.vals || !mod.vals.length) {
|
||||
delete entry[mod.type];
|
||||
} else {
|
||||
entry[mod.type] = mod.vals;
|
||||
}
|
||||
|
||||
break;
|
||||
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);
|
||||
});
|
||||
}
|
||||
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;
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
if (!entry[mod.type])
|
||||
return next(new ldap.NoSuchAttributeError(mod.type));
|
||||
case 'delete':
|
||||
if (!entry[mod.type])
|
||||
return next(new ldap.NoSuchAttributeError(mod.type));
|
||||
|
||||
delete entry[mod.type];
|
||||
delete entry[mod.type];
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
res.end();
|
||||
|
@ -149,50 +149,50 @@ header-font-family: google:Aldrich, Verdana, sans-serif
|
|||
server.search(SUFFIX, authorize, function(req, res, next) {
|
||||
var dn = req.dn.toString();
|
||||
if (!db[dn])
|
||||
return next(new ldap.NoSuchObjectError(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]
|
||||
});
|
||||
}
|
||||
if (req.filter.matches(db[dn])) {
|
||||
res.send({
|
||||
dn: dn,
|
||||
attributes: db[dn]
|
||||
});
|
||||
}
|
||||
|
||||
res.end();
|
||||
return next();
|
||||
res.end();
|
||||
return next();
|
||||
|
||||
case 'one':
|
||||
scopeCheck = function(k) {
|
||||
if (req.dn.equals(k))
|
||||
return true;
|
||||
scopeCheck = function(k) {
|
||||
if (req.dn.equals(k))
|
||||
return true;
|
||||
|
||||
var parent = ldap.parseDN(k).parent();
|
||||
return (parent ? parent.equals(req.dn) : false);
|
||||
};
|
||||
break;
|
||||
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));
|
||||
};
|
||||
scopeCheck = function(k) {
|
||||
return (req.dn.equals(k) || req.dn.parentOf(k));
|
||||
};
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
Object.keys(db).forEach(function(key) {
|
||||
if (!scopeCheck(key))
|
||||
return;
|
||||
if (!scopeCheck(key))
|
||||
return;
|
||||
|
||||
if (req.filter.matches(db[key])) {
|
||||
res.send({
|
||||
dn: key,
|
||||
attributes: db[key]
|
||||
});
|
||||
}
|
||||
if (req.filter.matches(db[key])) {
|
||||
res.send({
|
||||
dn: key,
|
||||
attributes: db[key]
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
res.end();
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
---
|
||||
title: ldapjs
|
||||
brand: spartan
|
||||
markdown2extras: wiki-tables
|
||||
logo-color: green
|
||||
logo-font-family: google:Aldrich, Verdana, sans-serif
|
||||
header-font-family: google:Aldrich, Verdana, sans-serif
|
||||
---
|
||||
|
||||
# Overview
|
||||
|
||||
This documents the ldapjs server API; this assumes that you are familiar with
|
||||
LDAP, so if you're not, hit the [guide](http://ldapjs.org/guide.html) first.
|
||||
|
||||
LDAP search filters are really the backbone of LDAP search operations, and
|
||||
ldapjs tries to get you in "easy" with them if your dataset is small, and also
|
||||
lets you introspect them if you want to write a "query planner". For reference,
|
||||
make sure to read over [RFC2254](http://www.ietf.org/rfc/rfc2254.txt), as this
|
||||
explains the LDAPv3 text filter representation.
|
||||
|
||||
Basically, ldapjs gives you a distinct object type mapping to each filter that
|
||||
is context-sensitive. However, _all_ filters have a `matches()` api on them, if
|
||||
that's all you need. Most filters will have an `attribute` property on them,
|
||||
since "simple" filters all operate on an attribute/value assertion. The
|
||||
"complex" filters are really aggregations of other filters (i.e. 'and'), and so
|
||||
these don't provide that property.
|
||||
|
||||
All Filters in the ldapjs framework extend from `Filter`, which wil have the
|
||||
property `type` available; this will return a string name for the filter, and
|
||||
will be one of:
|
||||
|
||||
* _equal:_ an `EqualityFilter`
|
||||
* _present:_ a `PresenceFilter`
|
||||
* _substring:_ a `SubstringFilter`
|
||||
* _ge:_ a `GreaterThanEqualsFilter`
|
||||
* _le:_ a `LessThanEqualsFilter`
|
||||
* _and:_ an `AndFilter`
|
||||
* _or:_ an `OrFilter`
|
||||
* _not:_ a `NotFilter`
|
||||
* _approx:_ an `ApproximateMatchFilter` (quasi-supported in ldapjs)
|
||||
* _ext:_ an `ExtensibleMatchFilter` (not supported in ldapjs)
|
||||
|
||||
# parseFilter(filterString)
|
||||
|
||||
Parses an [RFC2254](http://www.ietf.org/rfc/rfc2254.txt) filter string into an
|
||||
ldapjs object(s). If the filter is "complex", it will be a "tree" of objects.
|
||||
For example:
|
||||
|
||||
var parseFilter = require('ldapjs').parseFilter;
|
||||
|
||||
var f = parseFilter('(objectclass=*)');
|
||||
|
||||
Is a "simple" filter, and would just return a `PresenceFilter` object. However,
|
||||
|
||||
var f = parseFilter('(&(employeeType=manager)(l=Seattle))');
|
||||
|
||||
Would return an `AndFilter`, which would have a `filters` array of two
|
||||
`EqualityFilter` objects.
|
||||
|
||||
Note that `parseFilter` will throw if an invalid string is passed in
|
||||
(that is, a syntactically invalid string). All filter objects in th
|
||||
|
||||
# EqualityFilter
|
||||
|
||||
The equality filter is used to check exact matching of attribute/value
|
||||
assertions. This object will have an `attribute` and `value` property, and the
|
||||
`name` proerty will be `equal`.
|
||||
|
||||
The string syntax for an equality filter is `(attr=value)`.
|
||||
|
||||
The `matches()` method will return true IFF the passed in object has a
|
||||
key matching `attribute` and a value matching `value`.
|
||||
|
||||
var f = new EqualityFilter({
|
||||
attribute: 'cn',
|
||||
value: 'foo'
|
||||
});
|
||||
|
||||
f.matches({cn: 'foo'}); => true
|
||||
f.matches({cn: 'bar'}); => false
|
||||
|
||||
Note that "strict" equality matching is used, and by default everything in
|
||||
ldapjs (and LDAP) is a UTF-8 string. If you want comparison of numbers, or
|
||||
something else, you'll need to use a middleware interceptor that transforms
|
||||
values of objects.
|
||||
|
||||
# PresenceFilter
|
||||
|
||||
The presence filter is used to check if an object has an attribute at all, with
|
||||
any value. This object will have an `attribute` property, and the `name`
|
||||
property will be `present`.
|
||||
|
||||
The string syntax for a presence filter is `(attr=*)`.
|
||||
|
||||
The `matches()` method will return true IFF the passed in object has a
|
||||
key matching `attribute`.
|
||||
|
||||
var f = new PresenceFilter({
|
||||
attribute: 'cn'
|
||||
});
|
||||
|
||||
f.matches({cn: 'foo'}); => true
|
||||
f.matches({sn: 'foo'}); => false
|
||||
|
||||
# SubstringFilter
|
||||
|
||||
The substring filter is used to do wildcard matching of a string value. This
|
||||
object will have an `attribute` property and then it will have an `initial`
|
||||
property, which is the prefix match, an `any` which will be an array of strings
|
||||
that are to be found _somewhere_ in the target string, and a `final` property,
|
||||
which will be the suffix match of the string. `any` and `final` are both
|
||||
optional. The `name` property will be `substring`.
|
||||
|
||||
The string syntax for a presence filter is `(attr=foo*bar*cat*dog)`, which would
|
||||
map to:
|
||||
{
|
||||
initial: 'foo',
|
||||
any: ['bar', 'cat'],
|
||||
final: 'dog'
|
||||
}
|
||||
|
||||
The `matches()` method will return true IFF the passed in object has a
|
||||
key matching `attribute` and the "regex" matches the value
|
||||
|
||||
var f = new SubstringFilter({
|
||||
attribute: 'cn',
|
||||
initial: 'foo',
|
||||
any: ['bar'],
|
||||
final: 'baz'
|
||||
});
|
||||
|
||||
f.matches({cn: 'foobigbardogbaz'}); => true
|
||||
f.matches({sn: 'fobigbardogbaz'}); => false
|
||||
|
||||
# GreaterThanEqualsFilter
|
||||
|
||||
The ge filter is used to do comparisons and ordering based on the value type. As
|
||||
mentioned elsewhere, by default everything in LDAP and ldapjs is a string, so
|
||||
this filter's `matches()` would be using lexicographical ordering of strings.
|
||||
If you wanted `>=` semantics over numeric values, you would need to add some
|
||||
middleware to convert values before comparison (and the value of the filter).
|
||||
Note that the ldapjs schema middleware will do this.
|
||||
|
||||
The GreaterThanEqualsFilter will have an `attribute` property, a `value`
|
||||
property and the `name` property will be `ge`.
|
||||
|
||||
The string syntax for a ge filter is:
|
||||
|
||||
(cn>=foo)
|
||||
|
||||
The `matches()` method will return true IFF the passed in object has a
|
||||
key matching `attribute` and the value is `>=` this filter's `value`.
|
||||
|
||||
var f = new GreaterThanEqualsFilter({
|
||||
attribute: 'cn',
|
||||
value: 'foo',
|
||||
});
|
||||
|
||||
f.matches({cn: 'foobar'}); => true
|
||||
f.matches({cn: 'abc'}); => false
|
||||
|
||||
# LessThanEqualsFilter
|
||||
|
||||
The le filter is used to do comparisons and ordering based on the value type. As
|
||||
mentioned elsewhere, by default everything in LDAP and ldapjs is a string, so
|
||||
this filter's `matches()` would be using lexicographical ordering of strings.
|
||||
If you wanted `<=` semantics over numeric values, you would need to add some
|
||||
middleware to convert values before comparison (and the value of the filter).
|
||||
Note that the ldapjs schema middleware will do this.
|
||||
|
||||
The string syntax for a le filter is:
|
||||
|
||||
(cn<=foo)
|
||||
|
||||
The LessThanEqualsFilter will have an `attribute` property, a `value`
|
||||
property and the `name` property will be `le`.
|
||||
|
||||
The `matches()` method will return true IFF the passed in object has a
|
||||
key matching `attribute` and the value is `<=` this filter's `value`.
|
||||
|
||||
var f = new LessThanEqualsFilter({
|
||||
attribute: 'cn',
|
||||
value: 'foo',
|
||||
});
|
||||
|
||||
f.matches({cn: 'abc'}); => true
|
||||
f.matches({cn: 'foo'}); => false
|
||||
|
||||
# AndFilter
|
||||
|
||||
The and filter is a complex filter that simply contains "child" filters. The
|
||||
object will have a `filters` property which is an array of `Filter` objects. The
|
||||
`name` property will be `and`.
|
||||
|
||||
The string syntax for an and filter is (assuming below we're and'ing two
|
||||
equality filters):
|
||||
|
||||
(&(cn=foo)(sn=bar))
|
||||
|
||||
The `matches()` method will return true IFF the passed in object matches all
|
||||
the filters in the `filters` array.
|
||||
|
||||
var f = new AndFilter({
|
||||
filters: [
|
||||
new EqualityFilter({
|
||||
attribute: 'cn',
|
||||
value: 'foo'
|
||||
}),
|
||||
new EqualityFilter({
|
||||
attribute: 'sn',
|
||||
value: 'bar'
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
f.matches({cn: 'foo', sn: 'bar'}); => true
|
||||
f.matches({cn: 'foo', sn: 'baz'}); => false
|
||||
|
||||
# OrFilter
|
||||
|
||||
The or filter is a complex filter that simply contains "child" filters. The
|
||||
object will have a `filters` property which is an array of `Filter` objects. The
|
||||
`name` property will be `or`.
|
||||
|
||||
The string syntax for an or filter is (assuming below we're or'ing two
|
||||
equality filters):
|
||||
|
||||
(|(cn=foo)(sn=bar))
|
||||
|
||||
The `matches()` method will return true IFF the passed in object matches *any*
|
||||
of the filters in the `filters` array.
|
||||
|
||||
var f = new OrFilter({
|
||||
filters: [
|
||||
new EqualityFilter({
|
||||
attribute: 'cn',
|
||||
value: 'foo'
|
||||
}),
|
||||
new EqualityFilter({
|
||||
attribute: 'sn',
|
||||
value: 'bar'
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
f.matches({cn: 'foo', sn: 'baz'}); => true
|
||||
f.matches({cn: 'bar', sn: 'baz'}); => false
|
||||
|
||||
# NotFilter
|
||||
|
||||
The not filter is a complex filter that contains a single "child" filter. The
|
||||
object will have a `filter` property which is an instance of a `Filter` object.
|
||||
The `name` property will be `not`.
|
||||
|
||||
The string syntax for a not filter is (assuming below we're not'ing an
|
||||
equality filter):
|
||||
|
||||
(!(cn=foo))
|
||||
|
||||
The `matches()` method will return true IFF the passed in object does not match
|
||||
the filter in the `filter` property.
|
||||
|
||||
var f = new NotFilter({
|
||||
filter: new EqualityFilter({
|
||||
attribute: 'cn',
|
||||
value: 'foo'
|
||||
})
|
||||
});
|
||||
|
||||
f.matches({cn: 'bar'}); => true
|
||||
f.matches({cn: 'foo'}); => false
|
||||
|
||||
# ApproximateFilter
|
||||
|
||||
The approximate filter is used to check "approximate" matching of
|
||||
attribute/value assertions. This object will have an `attribute` and
|
||||
`value` property, and the `name` proerty will be `approx`.
|
||||
|
||||
As a side point, this is a useless filter. It's really only here if you have
|
||||
some whacky client that's sending this. It just does an exact match (which
|
||||
is what ActiveDirectory does too).
|
||||
|
||||
The string syntax for an equality filter is `(attr~=value)`.
|
||||
|
||||
The `matches()` method will return true IFF the passed in object has a
|
||||
key matching `attribute` and a value exactly matching `value`.
|
||||
|
||||
var f = new ApproximateFilter({
|
||||
attribute: 'cn',
|
||||
value: 'foo'
|
||||
});
|
||||
|
||||
f.matches({cn: 'foo'}); => true
|
||||
f.matches({cn: 'bar'}); => false
|
||||
|
|
@ -0,0 +1,562 @@
|
|||
---
|
||||
title: ldapjs
|
||||
brand: spartan
|
||||
markdown2extras: wiki-tables
|
||||
logo-color: green
|
||||
logo-font-family: google:Aldrich, Verdana, sans-serif
|
||||
header-font-family: google:Aldrich, Verdana, sans-serif
|
||||
---
|
||||
|
||||
# Overview
|
||||
|
||||
This documents the ldapjs server API; this assumes that you are familiar with
|
||||
LDAP, so if you're not, hit the [guide](http://ldapjs.org/guide.html) first.
|
||||
|
||||
# Create a server
|
||||
|
||||
The code to create a new server looks like:
|
||||
|
||||
var server = ldap.createServer();
|
||||
|
||||
Full list of options:
|
||||
|
||||
* _log4js:_ You can optionally pass in a log4js instance that the client will
|
||||
get a logger from. You'll need to set the level to `TRACE` To get any output
|
||||
from the client.
|
||||
* _certificate:_ A PEM-encoded X.509 certificate; will cause this server to
|
||||
run in TLS mode.
|
||||
* _key:_ A PEM-encoded private key that corresponds to _certificate_ for SSL.
|
||||
|
||||
## Properties on server
|
||||
|
||||
### maxConnections
|
||||
|
||||
Set this property to reject connections when the server's connection count gets
|
||||
high.
|
||||
|
||||
### connections (getter only)
|
||||
|
||||
The number of concurrent connections on the server.
|
||||
|
||||
### url
|
||||
|
||||
Returns the fully qualified URL this server is listening on. For example:
|
||||
`ldaps://10.1.2.3:1636`. If you haven't yet called `listen`, it will always
|
||||
return `ldap://localhost:389`.
|
||||
|
||||
### Event: 'close'
|
||||
`function() {}`
|
||||
|
||||
Emitted when the server closes.
|
||||
|
||||
## Listening for requests
|
||||
|
||||
The LDAP server API wraps up and mirrors the node
|
||||
[listen](http://nodejs.org/docs/v0.4.11/api/net.html#server.listen) family of
|
||||
APIs.
|
||||
|
||||
After calling `listen`, the property `url` on the server object itself will be
|
||||
available.
|
||||
|
||||
Example:
|
||||
|
||||
server.listen(389, '127.0.0.1', function() {
|
||||
console.log(LDAP server listening at: ' + server.url);
|
||||
});
|
||||
|
||||
|
||||
### Port and Host
|
||||
`listen(port, [host], [callback])`
|
||||
|
||||
Begin accepting connections on the specified port and host. If the host is
|
||||
omitted, the server will accept connections directed to any IPv4 address
|
||||
(INADDR_ANY).
|
||||
|
||||
This function is asynchronous. The last parameter callback will be called when
|
||||
the server has been bound.
|
||||
|
||||
### Unix Domain Socket
|
||||
`listen(path, [callback])`
|
||||
|
||||
Start a UNIX socket server listening for connections on the given path.
|
||||
|
||||
This function is asynchronous. The last parameter callback will be called when
|
||||
the server has been bound.
|
||||
|
||||
### File descriptor
|
||||
`listenFD(fd)`
|
||||
|
||||
Start a server listening for connections on the given file descriptor.
|
||||
|
||||
This file descriptor must have already had the `bind(2)` and `listen(2)` system
|
||||
calls invoked on it. Additionally, it must be set non-blocking; try
|
||||
`fcntl(fd, F_SETFL, O_NONBLOCK)`.
|
||||
|
||||
# Routes
|
||||
|
||||
The LDAP server API is meant to be the LDAP-equivalent of the express/sinatra
|
||||
paradigm of programming. Essentially every method is of the form
|
||||
`OP(req, res, next)` where OP is one of bind, add, del, etc. You can chain
|
||||
handlers together by calling `next()` and ordering your functions in the
|
||||
definition of the route. For example:
|
||||
|
||||
function authorize(req, res, next) {
|
||||
if (!req.connection.ldap.bindDN.equals('cn=root'))
|
||||
return next(new ldap.InsufficientAccessRightsError());
|
||||
|
||||
return next();
|
||||
}
|
||||
|
||||
server.search('o=example', authorize, function(req, res, next) { ... });
|
||||
|
||||
Note that ldapjs is also slightly different, since it's often going to be backed
|
||||
to a DB-like entity, in that it also has an API where you can pass in a
|
||||
'backend' object. This is necessary if there are persistent connection pools,
|
||||
caching, etc. that need to be placed in an object.
|
||||
|
||||
For example [ldapjs-riak](https://github.com/mcavage/node-ldapjs-riak) is a
|
||||
complete implementation of the LDAP protocol over
|
||||
[Riak](http://www.basho.com/products_riak_overview.php). Getting an LDAP
|
||||
server up with riak looks like:
|
||||
|
||||
var ldap = require('ldapjs');
|
||||
var ldapRiak = require('ldapjs-riak');
|
||||
|
||||
var server = ldap.createServer();
|
||||
var backend = ldapRiak.createBackend({
|
||||
"host": "localhost",
|
||||
"port": 8098,
|
||||
"bucket": "example",
|
||||
"indexes": ["l", "cn"],
|
||||
"uniqueIndexes": ["uid"],
|
||||
"numConnections": 5
|
||||
});
|
||||
|
||||
server.add("o=example",
|
||||
backend,
|
||||
backend.add());
|
||||
...
|
||||
|
||||
Basically, the first parameter to an ldapjs route is always the point in the
|
||||
tree to mount the handler chain at. The second argument is _optionally_ a
|
||||
backend object, if applicable. After that you can pass in an arbitrary
|
||||
combination of functions in the form `f(req, res, next)` or Arrays of functions
|
||||
of the same signature (ldapjs will unroll them).
|
||||
|
||||
Unlike HTTP, LDAP operations do not have a heterogenous format, so each
|
||||
operation in the rest of the document includes documentation for the
|
||||
request/response objects appropriate to that operation type.
|
||||
|
||||
## Common Request Elements
|
||||
|
||||
All request objects has the `dn` getter on it, which is "context-sensitive"
|
||||
and returns the point in the tree that the operation wants to operate on. The
|
||||
LDAP protocol itself sadly doesn't define operations this way, and has a unique
|
||||
name for just about every op. So, ldapjs calls it `dn`. The DN object itself
|
||||
is documented at [DN](/dn.html).
|
||||
|
||||
All requests have an optional array of `Control` objects. `Control` will have
|
||||
the properties `type` (string), `criticality` (boolean), and optionally a string
|
||||
`value`.
|
||||
|
||||
All request objects will have a `connection` object, which is the `net.Socket`
|
||||
associated to this request. Off the `connection` object is an `ldap` object.
|
||||
The most important property to pay attention to there is the `bindDN` property
|
||||
which will be an instance of an `ldap.DN` object. This is what the client
|
||||
authenticated as on this connection. If the client didn't bind, then a DN object
|
||||
will be there defaulted to `cn=anonymous`.
|
||||
|
||||
Additionally, request will have a `logId` parameter you can use to uniquely
|
||||
identify the request/connection pair in logs (includes the LDAP messageID).
|
||||
|
||||
## Common Response Elements
|
||||
|
||||
All response objects will have an `end` method on them. By default, calling
|
||||
`res.end()` with no arguments will return SUCCESS (0x00) to the client
|
||||
(with the exception of `compare` which will return COMPARE_TRUE (0x06)). You
|
||||
can pass in a status code to the `end()` method to return an alternate status
|
||||
code.
|
||||
|
||||
However, it's more common/easier to use the `return next(new LDAPError())`
|
||||
pattern, since ldapjs will fill in the extra LDAPResult fields like matchedDN
|
||||
and error message for you.
|
||||
|
||||
## Errors
|
||||
|
||||
ldapjs includes an exception hierarchy that directly corresponds to the RFC list
|
||||
of error codes. The complete list is documented in [errors](/errors.html). But
|
||||
the paradigm is something defined like CONSTRAINT_VIOLATION in the RFC would be
|
||||
`ConstraintViolationError` in ldapjs. Upon calling `next(new LDAPError())`,
|
||||
ldapjs will _stop_ calling your handler chain. For example:
|
||||
|
||||
server.search('o=example',
|
||||
function(req, res, next) { return next(); },
|
||||
function(req, res, next) { return next(new ldap.OperationsError()); },
|
||||
function(req, res, next) { res.end(); }
|
||||
);
|
||||
|
||||
In the code snipped above, the third handler would never get invoked.
|
||||
|
||||
# Bind
|
||||
|
||||
Adds a mount in the tree to perform LDAP binds with. Example:
|
||||
|
||||
server.bind('ou=people, o=example', function(req, res, next) {
|
||||
console.log('bind DN: ' + req.dn.toString());
|
||||
console.log('bind PW: ' + req.credentials);
|
||||
res.end();
|
||||
});
|
||||
|
||||
## BindRequest
|
||||
|
||||
BindRequest objects have the following properties:
|
||||
|
||||
### version
|
||||
|
||||
The LDAP protocol version the client is requesting to run this connection on.
|
||||
Note that ldapjs only supports LDAP version 3.
|
||||
|
||||
### name
|
||||
|
||||
The DN the client is attempting to bind as (note this is the same as the `dn`
|
||||
property).
|
||||
|
||||
### authentication
|
||||
|
||||
The method of authentication. Right now only `simple` is supported.
|
||||
|
||||
### credentials
|
||||
|
||||
The credentials to go with the `name/authentication` pair. For `simple`, this
|
||||
will be the plain-text password.
|
||||
|
||||
## BindResponse
|
||||
|
||||
No extra methods above an `LDAPResult` API call.
|
||||
|
||||
# Add
|
||||
|
||||
Adds a mount in the tree to perform LDAP adds with. Example:
|
||||
|
||||
server.add('ou=people, o=example', function(req, res, next) {
|
||||
console.log('DN: ' + req.dn.toString());
|
||||
console.log('Entry attributes: ' + req.toObject().attributes);
|
||||
res.end();
|
||||
});
|
||||
|
||||
## AddRequest
|
||||
|
||||
AddRequest objects have the following properties:
|
||||
|
||||
### entry
|
||||
|
||||
The DN the client is attempting to add (note this is the same as the `dn`
|
||||
property).
|
||||
|
||||
### attributes
|
||||
|
||||
The set of attributes in this entry. Note that this will be an array of
|
||||
`Attribute` objects (which have a type and an array of values). This directly
|
||||
maps to how the request came in off the wire. It's likely you'll want to use
|
||||
`toObject()` and iterate that way, since that will transform an AddRequest into
|
||||
a standard JavaScript object.
|
||||
|
||||
### toObject()
|
||||
|
||||
This operation will return a plain JavaScript object from the request that looks
|
||||
like:
|
||||
|
||||
{
|
||||
dn: 'cn=foo, o=example', // string, not DN object
|
||||
attributes: {
|
||||
cn: ['foo'],
|
||||
sn: ['bar'],
|
||||
objectclass: ['person', 'top']
|
||||
}
|
||||
}
|
||||
|
||||
## AddResponse
|
||||
|
||||
No extra methods above an `LDAPResult` API call.
|
||||
|
||||
# Search
|
||||
|
||||
Adds a handler for the LDAP search operation. Example:
|
||||
|
||||
server.search('o=example', function(req, res, next) {
|
||||
console.log('base object: ' + req.dn.toString());
|
||||
console.log('scope: ' + req.scope);
|
||||
console.log('filter: ' + req.filter.toString());
|
||||
res.end();
|
||||
});
|
||||
|
||||
|
||||
this.derefAliases = options.derefAliases || Protocol.NEVER_DEREF_ALIASES;
|
||||
this.sizeLimit = options.sizeLimit || 0;
|
||||
this.timeLimit = options.timeLimit || 00;
|
||||
this.typesOnly = options.typesOnly || false;
|
||||
this.filter = options.filter || null;
|
||||
this.attributes = options.attributes ? options.attributes.slice(0) : [];
|
||||
|
||||
## SearchRequest
|
||||
|
||||
SearchRequest objects have the following properties:
|
||||
|
||||
### baseObject
|
||||
|
||||
The DN the client is attempting to start the search at (equivalent to `dn`).
|
||||
|
||||
### scope
|
||||
|
||||
(string) one of:
|
||||
|
||||
* base
|
||||
* one
|
||||
* sub
|
||||
|
||||
### derefAliases
|
||||
|
||||
Will be an integer (defined in the LDAP protocol). Defaults to '0' (meaning
|
||||
never deref).
|
||||
|
||||
### sizeLimit
|
||||
|
||||
The number of entries to return. Defaults to '0' (unlimited). ldapjs doesn't
|
||||
currently automatically enforce this, but probably will at some point.
|
||||
|
||||
### timeLimit
|
||||
|
||||
Maximum amount of time the server should take in sending search entries.
|
||||
Defaults to '0' (unlimited).
|
||||
|
||||
### typesOnly
|
||||
|
||||
Whether to return only the names of attributes, and not the values. Defaults to
|
||||
false. Note that ldapjs will take care of this for you.
|
||||
|
||||
### filter
|
||||
|
||||
The [filter](/filters.html) object that the client requested. Notably this has
|
||||
a `matches()` api on it that you can leverage. For an example of introspecting
|
||||
a filter, take a look at the ldapjs-riak source.
|
||||
|
||||
### attributes
|
||||
|
||||
An optional list of attributes to restrict the returned result sets to. ldapjs
|
||||
will automatically handle this for you.
|
||||
|
||||
## SearchResponse
|
||||
|
||||
### send(entry)
|
||||
|
||||
Allows you to send a `SearchEntry` object. Note that you do not need to
|
||||
explicitly pass in a `SearchEntry` object, and can instead just send a plain
|
||||
JavaScript object that matches the format used from `AddRequest.toObject()`.
|
||||
Example:
|
||||
|
||||
server.search('o=example', function(req, res, next) {
|
||||
var obj = {
|
||||
dn: 'o=example',
|
||||
attributes: {
|
||||
objectclass: ['top', 'organization'],
|
||||
o: ['example']
|
||||
}
|
||||
};
|
||||
|
||||
if (req.filter.matches(obj))
|
||||
res.send(obj)
|
||||
|
||||
res.end();
|
||||
});
|
||||
|
||||
# modify
|
||||
|
||||
Allows you to handle an LDAP modify operation. Example:
|
||||
|
||||
server.modify('o=example', function(req, res, next) {
|
||||
console.log('DN: ' + req.dn.toString());
|
||||
console.log('changes:');
|
||||
req.changes.forEach(function(c) {
|
||||
console.log(' operation: ' + c.operation);
|
||||
console.log(' modification: ' + c.modification.toString());
|
||||
});
|
||||
res.end();
|
||||
});
|
||||
|
||||
## ModifyRequest
|
||||
|
||||
ModifyRequest objects have the following properties:
|
||||
|
||||
### object
|
||||
|
||||
The DN the client is attempting to update (note this is the same as the `dn`
|
||||
property).
|
||||
|
||||
### changes
|
||||
|
||||
An array of `Change` objects the client is attempting to perform. See below for
|
||||
details on the `Change` object.
|
||||
|
||||
## Change
|
||||
|
||||
The Change object will have the following properties:
|
||||
|
||||
### operation
|
||||
|
||||
A string, and will be one of: 'add', 'delete', 'replace'.
|
||||
|
||||
### modification
|
||||
|
||||
Will be an `Attribute` object, which will have a 'type' (string) field, and
|
||||
'vals', which will be an array of string values.
|
||||
|
||||
## ModifyResponse
|
||||
|
||||
No extra methods above an `LDAPResult` API call.
|
||||
|
||||
# del
|
||||
|
||||
Allows you to handle an LDAP delete operation. Example:
|
||||
|
||||
server.delete('o=example', function(req, res, next) {
|
||||
console.log('DN: ' + req.dn.toString());
|
||||
res.end();
|
||||
});
|
||||
|
||||
## DeleteRequest
|
||||
|
||||
### entry
|
||||
|
||||
The DN the client is attempting to delete (note this is the same as the `dn`
|
||||
property).
|
||||
|
||||
## DeleteResponse
|
||||
|
||||
No extra methods above an `LDAPResult` API call.
|
||||
|
||||
# compare
|
||||
|
||||
Allows you to handle an LDAP compare operation. Example:
|
||||
|
||||
server.compare('o=example', function(req, res, next) {
|
||||
console.log('DN: ' + req.dn.toString());
|
||||
console.log('attribute name: ' + req.attribute);
|
||||
console.log('attribute value: ' + req.value);
|
||||
res.end(req.value === 'foo');
|
||||
});
|
||||
|
||||
## CompareRequest
|
||||
|
||||
### entry
|
||||
|
||||
The DN the client is attempting to compare (note this is the same as the `dn`
|
||||
property).
|
||||
|
||||
### attribute
|
||||
|
||||
Will be the string name of the attribute to compare values of.
|
||||
|
||||
### value
|
||||
|
||||
The string value of the attribute to compare.
|
||||
|
||||
## CompareResponse
|
||||
|
||||
The `end()` method for compare takes a boolean, as opposed to a numeric code
|
||||
(note you can still pass in a numeric LDAP status code if you want). Beyond
|
||||
that, there are no extra methods above an `LDAPResult` API call.
|
||||
|
||||
# modifyDN
|
||||
|
||||
Allows you to handle an LDAP modifyDN operation. Example:
|
||||
|
||||
server.modifyDN('o=example', function(req, res, next) {
|
||||
console.log('DN: ' + req.dn.toString());
|
||||
console.log('new RDN: ' + req.newRdn.toString());
|
||||
console.log('deleteOldRDN: ' + req.deleteOldRdn);
|
||||
console.log('new superior: ' +
|
||||
(req.newSuperior ? req.newSuperior.toString() : ''));
|
||||
|
||||
res.end();
|
||||
});
|
||||
|
||||
## ModifyDNRequest
|
||||
|
||||
### entry
|
||||
|
||||
The DN the client is attempting to rename (note this is the same as the `dn`
|
||||
property).
|
||||
|
||||
### newRdn
|
||||
|
||||
The leaf RDN the client wants to rename this entry to. This will be a DN object.
|
||||
|
||||
### deleteOldRdn
|
||||
|
||||
boolean. Whether or not to delete the old RDN (i.e., rename vs copy). Defaults
|
||||
to true.
|
||||
|
||||
### newSuperior
|
||||
|
||||
Optional (DN). If the modifyDN operation wishes to relocate the entry in the
|
||||
tree, the newSuperior field will contain the new parent.
|
||||
|
||||
## ModifyDNResponse
|
||||
|
||||
No extra methods above an `LDAPResult` API call.
|
||||
|
||||
# exop
|
||||
|
||||
Allows you to handle an LDAP extended operation. Extended operations are pretty
|
||||
much arbitrary extensions, by definition. Typically the extended 'name' is an
|
||||
OID, but ldapjs makes no such restrictions; it just needs to be a string. Note
|
||||
that unlike the other operations, extended operations don't map to any location
|
||||
in the tree, so routing here will be exact match, as opposed to subtree.
|
||||
Example:
|
||||
|
||||
// LDAP whoami
|
||||
server.exop('1.3.6.1.4.1.4203.1.11.3', function(req, res, next) {
|
||||
console.log('name: ' + req.name);
|
||||
console.log('value: ' + req.value);
|
||||
res.value = 'u:xxyyz@EXAMPLE.NET';
|
||||
res.end();
|
||||
return next();
|
||||
});
|
||||
|
||||
## ExtendedRequest
|
||||
|
||||
### name
|
||||
|
||||
String. Will always be a match to the route-defined name. But the client
|
||||
includes this in their requests.
|
||||
|
||||
### value
|
||||
|
||||
Optional string. The arbitrary blob the client sends for this extended
|
||||
operation.
|
||||
|
||||
## ExtendedResponse
|
||||
|
||||
### name
|
||||
|
||||
The name of the extended operation. ldapjs will automatically set this.
|
||||
|
||||
### value
|
||||
|
||||
The arbitrary (string) value to send back as part of the response.
|
||||
|
||||
# unbind
|
||||
|
||||
ldapjs by default provides an unbind handler that just disconnects the client
|
||||
and cleans up any internals (in ldapjs core). You can override this handler
|
||||
if you need to clean up any items in your backend, for example.
|
||||
|
||||
server.unbind(function(req, res, next) {
|
||||
res.end();
|
||||
});
|
||||
|
||||
Note that the LDAP unbind operation actually doesn't send any response (by
|
||||
definition in the RFC), so the UnbindResponse is really just a stub that
|
||||
ultimately calls `net.Socket.end()` for you. There are no properties available
|
||||
on either the request or response objects, except of course for `end()` on the
|
||||
response.
|
|
@ -44,7 +44,7 @@ function ModifyDNRequest(options) {
|
|||
|
||||
this.entry = options.entry || null;
|
||||
this.newRdn = options.newRdn || null;
|
||||
this.deleteOldRdn = options.deleteOldRdn || false;
|
||||
this.deleteOldRdn = options.deleteOldRdn || true;
|
||||
this.newSuperior = options.newSuperior || null;
|
||||
|
||||
var self = this;
|
||||
|
|
|
@ -71,7 +71,7 @@ function SearchRequest(options) {
|
|||
this.scope = options.scope || 'base';
|
||||
this.derefAliases = options.derefAliases || Protocol.NEVER_DEREF_ALIASES;
|
||||
this.sizeLimit = options.sizeLimit || 0;
|
||||
this.timeLimit = options.timeLimit || 00;
|
||||
this.timeLimit = options.timeLimit || 0;
|
||||
this.typesOnly = options.typesOnly || false;
|
||||
this.filter = options.filter || null;
|
||||
this.attributes = options.attributes ? options.attributes.slice(0) : [];
|
||||
|
|
|
@ -8,6 +8,7 @@ var asn1 = require('asn1');
|
|||
var LDAPMessage = require('./message');
|
||||
var LDAPResult = require('./result');
|
||||
|
||||
var DN = require('../dn').DN;
|
||||
var Protocol = require('../protocol');
|
||||
|
||||
|
||||
|
@ -32,7 +33,7 @@ function UnbindRequest(options) {
|
|||
LDAPMessage.call(this, options);
|
||||
|
||||
this.__defineGetter__('type', function() { return 'UnbindRequest'; });
|
||||
this.__defineGetter__('_dn', function() { return ''; });
|
||||
this.__defineGetter__('_dn', function() { return new DN([{}]); });
|
||||
}
|
||||
util.inherits(UnbindRequest, LDAPMessage);
|
||||
module.exports = UnbindRequest;
|
||||
|
|
|
@ -237,7 +237,7 @@ function Server(options) {
|
|||
});
|
||||
|
||||
c.ldap.__defineGetter__('bindDN', function() {
|
||||
return c.ldap._bindDN || 'cn=anonymous';
|
||||
return c.ldap._bindDN || new DN([{cn: 'anonymous'}]);
|
||||
});
|
||||
c.ldap.__defineSetter__('bindDN', function(val) {
|
||||
if (!(val instanceof DN))
|
||||
|
|
Loading…
Reference in New Issue