GH-28 Support extensible filters (client only)
This commit is contained in:
parent
920b9e00f4
commit
aedd9f222c
|
@ -0,0 +1,107 @@
|
||||||
|
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
|
||||||
|
|
||||||
|
var assert = require('assert');
|
||||||
|
var util = require('util');
|
||||||
|
|
||||||
|
var Filter = require('./filter');
|
||||||
|
|
||||||
|
var Protocol = require('../protocol');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///--- API
|
||||||
|
|
||||||
|
function ExtensibleFilter(options) {
|
||||||
|
if (typeof(options) === 'object') {
|
||||||
|
if (options.rule && typeof(options.rule) !== 'string')
|
||||||
|
throw new TypeError('options.rule must be a string');
|
||||||
|
if (options.matchType && typeof(options.matchType) !== 'string')
|
||||||
|
throw new TypeError('options.type must be a string');
|
||||||
|
if (options.value && typeof(options.value) !== 'string')
|
||||||
|
throw new TypeError('options.value (string) required');
|
||||||
|
} else {
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.matchType = options.matchType || null;
|
||||||
|
this.rule = options.rule || null;
|
||||||
|
this.value = options.value || '';
|
||||||
|
this.dnAttributes = options.dnAttributes || false;
|
||||||
|
options.type = Protocol.FILTER_EXT;
|
||||||
|
Filter.call(this, options);
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
this.__defineGetter__('json', function() {
|
||||||
|
return {
|
||||||
|
type: 'ExtensibleMatch',
|
||||||
|
matchRule: self.rule,
|
||||||
|
matchType: self.matchType,
|
||||||
|
matchValue: self.value,
|
||||||
|
dnAttributes: self.dnAttributes
|
||||||
|
};
|
||||||
|
});
|
||||||
|
this.__defineGetter__('matchingRule', function() {
|
||||||
|
return self.rule;
|
||||||
|
});
|
||||||
|
this.__defineGetter__('matchValue', function() {
|
||||||
|
return self.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
util.inherits(ExtensibleFilter, Filter);
|
||||||
|
module.exports = ExtensibleFilter;
|
||||||
|
|
||||||
|
|
||||||
|
ExtensibleFilter.prototype.toString = function() {
|
||||||
|
var str = '(';
|
||||||
|
|
||||||
|
if (this.matchType)
|
||||||
|
str += this.matchType;
|
||||||
|
|
||||||
|
str += ':';
|
||||||
|
|
||||||
|
if (this.dnAttributes)
|
||||||
|
str += 'dn:';
|
||||||
|
|
||||||
|
if (this.rule)
|
||||||
|
str += this.rule + ':';
|
||||||
|
|
||||||
|
return (str + '=' + this.value + ')');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* THIS IS A STUB!
|
||||||
|
*
|
||||||
|
* ldapjs does not support server side extensible matching. This class exists
|
||||||
|
* only for the client to send them.
|
||||||
|
*
|
||||||
|
* @param {Object} target the target object.
|
||||||
|
* @return {Boolean} false always.
|
||||||
|
*/
|
||||||
|
ExtensibleFilter.prototype.matches = function(target) {
|
||||||
|
if (typeof(target) !== 'object')
|
||||||
|
throw new TypeError('target (object) required');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ExtensibleFilter.prototype.parse = function(ber) {
|
||||||
|
throw new Error('ExtensibleFilter not supported');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ExtensibleFilter.prototype._toBer = function(ber) {
|
||||||
|
assert.ok(ber);
|
||||||
|
|
||||||
|
if (this.rule)
|
||||||
|
ber.writeString(this.rule, 0x81);
|
||||||
|
if (this.matchType)
|
||||||
|
ber.writeString(this.matchType, 0x82);
|
||||||
|
|
||||||
|
ber.writeString(this.value, 0x83);
|
||||||
|
if (this.dnAttributes)
|
||||||
|
ber.writeBoolean(this.dnAttributes, 0x84);
|
||||||
|
|
||||||
|
return ber;
|
||||||
|
};
|
|
@ -10,6 +10,7 @@ var Filter = require('./filter');
|
||||||
var AndFilter = require('./and_filter');
|
var AndFilter = require('./and_filter');
|
||||||
var ApproximateFilter = require('./approx_filter');
|
var ApproximateFilter = require('./approx_filter');
|
||||||
var EqualityFilter = require('./equality_filter');
|
var EqualityFilter = require('./equality_filter');
|
||||||
|
var ExtensibleFilter = require('./ext_filter');
|
||||||
var GreaterThanEqualsFilter = require('./ge_filter');
|
var GreaterThanEqualsFilter = require('./ge_filter');
|
||||||
var LessThanEqualsFilter = require('./le_filter');
|
var LessThanEqualsFilter = require('./le_filter');
|
||||||
var NotFilter = require('./not_filter');
|
var NotFilter = require('./not_filter');
|
||||||
|
@ -123,7 +124,7 @@ function _parseString(str) {
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
switch (stack[i].op) {
|
switch (stack[i].op) {
|
||||||
case '=': // could be presence, equality or substr
|
case '=': // could be presence, equality, substr or ext
|
||||||
if (stack[i].value === '*') {
|
if (stack[i].value === '*') {
|
||||||
filters.push(new PresenceFilter(stack[i]));
|
filters.push(new PresenceFilter(stack[i]));
|
||||||
} else {
|
} else {
|
||||||
|
@ -150,7 +151,32 @@ function _parseString(str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (vals.length === 1) {
|
if (vals.length === 1) {
|
||||||
filters.push(new EqualityFilter(stack[i]));
|
if (stack[i].attribute.indexOf(':') !== -1) {
|
||||||
|
var extTmp = stack[i].attribute.split(':');
|
||||||
|
var extOpts = {};
|
||||||
|
extOpts.matchType = extTmp[0];
|
||||||
|
switch (extTmp.length) {
|
||||||
|
case 2:
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (extTmp[1].toLowerCase() === 'dn') {
|
||||||
|
extOpts.dnAttributes = true;
|
||||||
|
} else {
|
||||||
|
extOpts.rule = extTmp[1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
extOpts.dnAttributes = true;
|
||||||
|
extOpts.rule = extTmp[2];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid extensible filter');
|
||||||
|
}
|
||||||
|
extOpts.value = vals[0];
|
||||||
|
filters.push(new ExtensibleFilter(extOpts));
|
||||||
|
} else {
|
||||||
|
filters.push(new EqualityFilter(stack[i]));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
filters.push(new SubstringFilter({
|
filters.push(new SubstringFilter({
|
||||||
attribute: stack[i].attribute,
|
attribute: stack[i].attribute,
|
||||||
|
@ -245,6 +271,11 @@ function _parse(ber) {
|
||||||
f.parse(ber);
|
f.parse(ber);
|
||||||
return f;
|
return f;
|
||||||
|
|
||||||
|
case Protocol.FILTER_EXT:
|
||||||
|
f = new ExtensibleFilter();
|
||||||
|
f.parse(ber);
|
||||||
|
return f;
|
||||||
|
|
||||||
case Protocol.FILTER_GE:
|
case Protocol.FILTER_GE:
|
||||||
f = new GreaterThanEqualsFilter();
|
f = new GreaterThanEqualsFilter();
|
||||||
f.parse(ber);
|
f.parse(ber);
|
||||||
|
@ -309,6 +340,7 @@ module.exports = {
|
||||||
AndFilter: AndFilter,
|
AndFilter: AndFilter,
|
||||||
ApproximateFilter: ApproximateFilter,
|
ApproximateFilter: ApproximateFilter,
|
||||||
EqualityFilter: EqualityFilter,
|
EqualityFilter: EqualityFilter,
|
||||||
|
ExtensibleFilter: ExtensibleFilter,
|
||||||
GreaterThanEqualsFilter: GreaterThanEqualsFilter,
|
GreaterThanEqualsFilter: GreaterThanEqualsFilter,
|
||||||
LessThanEqualsFilter: LessThanEqualsFilter,
|
LessThanEqualsFilter: LessThanEqualsFilter,
|
||||||
NotFilter: NotFilter,
|
NotFilter: NotFilter,
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
|
||||||
|
|
||||||
|
var test = require('tap').test;
|
||||||
|
|
||||||
|
var asn1 = require('asn1');
|
||||||
|
|
||||||
|
|
||||||
|
///--- Globals
|
||||||
|
|
||||||
|
var ExtensibleFilter;
|
||||||
|
var BerReader = asn1.BerReader;
|
||||||
|
var BerWriter = asn1.BerWriter;
|
||||||
|
var filters;
|
||||||
|
|
||||||
|
|
||||||
|
///--- Tests
|
||||||
|
|
||||||
|
test('load library', function(t) {
|
||||||
|
filters = require('../../lib/index').filters;
|
||||||
|
t.ok(filters);
|
||||||
|
ExtensibleFilter = filters.ExtensibleFilter;
|
||||||
|
t.ok(ExtensibleFilter);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('Construct no args', function(t) {
|
||||||
|
var f = new ExtensibleFilter();
|
||||||
|
t.ok(f);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('Construct args', function(t) {
|
||||||
|
var f = new ExtensibleFilter({
|
||||||
|
matchType: 'foo',
|
||||||
|
value: 'bar',
|
||||||
|
});
|
||||||
|
t.ok(f);
|
||||||
|
t.equal(f.matchType, 'foo');
|
||||||
|
t.equal(f.value, 'bar');
|
||||||
|
t.equal(f.toString(), '(foo:=bar)');
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('parse RFC example 1', function(t) {
|
||||||
|
var f = filters.parseString('(cn:caseExactMatch:=Fred Flintstone)');
|
||||||
|
t.ok(f);
|
||||||
|
t.equal(f.matchType, 'cn');
|
||||||
|
t.equal(f.matchingRule, 'caseExactMatch');
|
||||||
|
t.equal(f.matchValue, 'Fred Flintstone');
|
||||||
|
t.notOk(f.dnAttributes);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('parse RFC example 2', function(t) {
|
||||||
|
var f = filters.parseString('(cn:=Betty Rubble)');
|
||||||
|
t.ok(f);
|
||||||
|
t.equal(f.matchType, 'cn');
|
||||||
|
t.equal(f.matchValue, 'Betty Rubble');
|
||||||
|
t.notOk(f.dnAttributes);
|
||||||
|
t.notOk(f.matchingRule);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('parse RFC example 3', function(t) {
|
||||||
|
var f = filters.parseString('(sn:dn:2.4.6.8.10:=Barney Rubble)');
|
||||||
|
t.ok(f);
|
||||||
|
t.equal(f.matchType, 'sn');
|
||||||
|
t.equal(f.matchingRule, '2.4.6.8.10');
|
||||||
|
t.equal(f.matchValue, 'Barney Rubble');
|
||||||
|
t.ok(f.dnAttributes);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('parse RFC example 3', function(t) {
|
||||||
|
var f = filters.parseString('(o:dn:=Ace Industry)');
|
||||||
|
t.ok(f);
|
||||||
|
t.equal(f.matchType, 'o');
|
||||||
|
t.notOk(f.matchingRule);
|
||||||
|
t.equal(f.matchValue, 'Ace Industry');
|
||||||
|
t.ok(f.dnAttributes);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('parse RFC example 4', function(t) {
|
||||||
|
var f = filters.parseString('(:1.2.3:=Wilma Flintstone)');
|
||||||
|
t.ok(f);
|
||||||
|
t.notOk(f.matchType);
|
||||||
|
t.equal(f.matchingRule, '1.2.3');
|
||||||
|
t.equal(f.matchValue, 'Wilma Flintstone');
|
||||||
|
t.notOk(f.dnAttributes);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('parse RFC example 5', function(t) {
|
||||||
|
var f = filters.parseString('(:DN:2.4.6.8.10:=Dino)');
|
||||||
|
t.ok(f);
|
||||||
|
t.notOk(f.matchType);
|
||||||
|
t.equal(f.matchingRule, '2.4.6.8.10');
|
||||||
|
t.equal(f.matchValue, 'Dino');
|
||||||
|
t.ok(f.dnAttributes);
|
||||||
|
t.end();
|
||||||
|
});
|
Loading…
Reference in New Issue