From c5ccafd436ac8d9b51e9be0b9baf2a8e997c6df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20S=C3=BCssemilch=20Poulain?= <jonathan@sofiero.net> Date: Fri, 16 May 2014 17:10:24 +0200 Subject: [PATCH 1/6] Server Side Sorting control --- lib/controls/index.js | 10 +- lib/controls/server_side_sorting_control.js | 117 ++++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 lib/controls/server_side_sorting_control.js diff --git a/lib/controls/index.js b/lib/controls/index.js index d2d7f23..4157d5f 100644 --- a/lib/controls/index.js +++ b/lib/controls/index.js @@ -7,6 +7,7 @@ var EntryChangeNotificationControl = require('./entry_change_notification_control'); var PersistentSearchControl = require('./persistent_search_control'); var PagedResultsControl = require('./paged_results_control'); +var ServerSideSortingControl = require('./server_side_sorting_control.js'); @@ -57,6 +58,12 @@ module.exports = { value: value }); break; + case ServerSideSortingControl.OID: + control = new ServerSideSortingControl({ + critical: critical, + value: value + }); + break; default: control = new Control({ type: type, @@ -72,5 +79,6 @@ module.exports = { Control: Control, EntryChangeNotificationControl: EntryChangeNotificationControl, PagedResultsControl: PagedResultsControl, - PersistentSearchControl: PersistentSearchControl + PersistentSearchControl: PersistentSearchControl, + ServerSideSortingControl: ServerSideSortingControl }; diff --git a/lib/controls/server_side_sorting_control.js b/lib/controls/server_side_sorting_control.js new file mode 100644 index 0000000..995a369 --- /dev/null +++ b/lib/controls/server_side_sorting_control.js @@ -0,0 +1,117 @@ +var assert = require('assert'); +var util = require('util'); + +var asn1 = require('asn1'); + +var Control = require('./control'); + + + +///--- Globals + +var BerReader = asn1.BerReader; +var BerWriter = asn1.BerWriter; + + + +///--- API + +function ServerSideSortingControl(options) { + if (!options) + options = {}; + + options.type = ServerSideSortingControl.OID; + if (options.value) { + if (Buffer.isBuffer(options.value)) { + this.parse(options.value); + } else if (Array.isArray(options.value)) { + for (var i = 0; i < options.value.length; i++) { + if (!typeof (options.value[i]) === 'object') { + throw new TypeError('Elements of options.value must be Objects'); + } else if (!options.value[i].hasOwnProperty('attributeType')) { + throw new Error('Missing required key: attributeType'); + } + } + this._value = options.value; + } else if (typeof (options.value) === 'object') { + if (!options.value.hasOwnProperty('attributeType')) { + throw new Error('Missing required key: attributeType'); + } + this._value = options.value; + } else { + throw new TypeError('options.value must be a Buffer, Array or Object'); + } + options.value = null; + } + Control.call(this, options); + + var self = this; + this.__defineGetter__('value', function () { + return self._value || {}; + }); +} +util.inherits(ServerSideSortingControl, Control); +module.exports = ServerSideSortingControl; + + +ServerSideSortingControl.prototype.parse = function parse(buffer) { + assert.ok(buffer); + + var ber = new BerReader(buffer); + if (ber.readSequence()) { + this._value = {}; + this._value.sortResult = ber.readInt(); + this._value.attributeType = ber.readString(asn1.Ber.OctetString, true); + //readString returns '' instead of a zero-length buffer + if (!this._value.attributeType) + this._value.attributeType = new Buffer(0); + + return true; + } + + return false; +}; + + +ServerSideSortingControl.prototype._toBer = function (ber) { + assert.ok(ber); + + if (!this._value) + return; + + var writer = new BerWriter(); + writer.startSequence(0x30); + + if (Array.isArray(this.value)) { + for (var i = 0; i < this.value.length; i++) { + this._sortKeyListItemToBer(writer, this.value[i]); + } + } else if (typeof (this.value) === 'object') { + this._sortKeyListItemToBer(writer, this.value); + } + + writer.endSequence(); + ber.writeBuffer(writer.buffer, 0x04); +}; + + +ServerSideSortingControl.prototype._json = function (obj) { + obj.controlValue = this.value; + return obj; +}; + +ServerSideSortingControl.prototype._sortKeyListItemToBer = function(writer, obj) { + writer.startSequence(0x30); + if (obj.attributeType) { + writer.writeString(obj.attributeType, asn1.Ber.OctetString); + } + if (obj.orderingRule) { + writer.writeString(obj.orderingRule, 0x80); + } + if (obj.reverseOrder) { + writer.writeBoolean(obj.reverseOrder, 0x81); + } + writer.endSequence(); +}; + +ServerSideSortingControl.OID = '1.2.840.113556.1.4.473'; From c1af9a8814a42bbee59bcd547ebc2fa1d53690b8 Mon Sep 17 00:00:00 2001 From: = <jonathan@sofiero.net> Date: Mon, 26 May 2014 21:12:14 +0000 Subject: [PATCH 2/6] Server side sorting control tests --- .../server_side_sorting_control_test.js | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 test/controls/server_side_sorting_control_test.js diff --git a/test/controls/server_side_sorting_control_test.js b/test/controls/server_side_sorting_control_test.js new file mode 100644 index 0000000..9cca748 --- /dev/null +++ b/test/controls/server_side_sorting_control_test.js @@ -0,0 +1,82 @@ + +var test = require('tap').test; + +var asn1 = require('asn1'); + +var BerReader = asn1.BerReader; +var BerWriter = asn1.BerWriter; +var getControl; +var ServerSideSortingControl; + +function bufferEqual(t, a, b) { + t.equal(a.toString('hex'), b.toString('hex')); +} + + +///--- Tests + + +test('load library', function (t) { + ServerSideSortingControl = + require('../../lib').ServerSideSortingControl; + t.ok(ServerSideSortingControl); + getControl = require('../../lib').getControl; + t.ok(getControl); + t.end(); +}); + + +test('new no args', function (t) { + t.ok(new ServerSideSortingControl()); + t.end(); +}); + + +test('new with args', function (t) { + var c = new ServerSideSortingControl({ + type: '1.2.840.113556.1.4.473', + criticality: true, + value: { + attributeType: 'sn' + } + }); + t.ok(c); + t.equal(c.type, '1.2.840.113556.1.4.473'); + t.ok(c.criticality); + t.equal(c.value.attributeType, 'sn'); + + var writer = new BerWriter(); + c.toBer(writer); + var reader = new BerReader(writer.buffer); + var sssc = getControl(reader); + t.ok(sssc); + console.log('sssc', sssc.value); + t.equal(sssc.type, '1.2.840.113556.1.4.473'); + t.ok(sssc.criticality); + t.equal(sssc.value.attributeType, 'sn'); + bufferEqual(t, sssc.value.cookie, new Buffer(['sn'])); + + t.end(); +}); + +test('tober', function (t) { + var sssc = new ServerSideSortingControl({ + type: '1.2.840.113556.1.4.473', + criticality: true, + value: { + attributeType: 'sn' + } + }); + + var ber = new BerWriter(); + sssc.toBer(ber); + + var c = getControl(new BerReader(ber.buffer)); + t.ok(c); + t.equal(c.type, '1.2.840.113556.1.4.473'); + t.ok(c.criticality); + t.equal(c.value.attributeType, 'sn'); + bufferEqual(t, c.value.cookie, new Buffer(0)); + + t.end(); +}); From b742e286dbc87f6c78fa5ee6d8b7b2c70bb6eb15 Mon Sep 17 00:00:00 2001 From: = <jonathan@sofiero.net> Date: Fri, 30 May 2014 20:57:06 +0000 Subject: [PATCH 3/6] Fixed parse method and added some tests --- lib/controls/server_side_sorting_control.js | 34 ++++++++--- .../server_side_sorting_control_test.js | 59 ++++++++++++------- 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/lib/controls/server_side_sorting_control.js b/lib/controls/server_side_sorting_control.js index 995a369..0f6308a 100644 --- a/lib/controls/server_side_sorting_control.js +++ b/lib/controls/server_side_sorting_control.js @@ -58,13 +58,18 @@ ServerSideSortingControl.prototype.parse = function parse(buffer) { assert.ok(buffer); var ber = new BerReader(buffer); - if (ber.readSequence()) { - this._value = {}; - this._value.sortResult = ber.readInt(); - this._value.attributeType = ber.readString(asn1.Ber.OctetString, true); - //readString returns '' instead of a zero-length buffer - if (!this._value.attributeType) - this._value.attributeType = new Buffer(0); + + if (ber.readSequence(0x30)) { + this._value = []; + + while (ber.readSequence(0x30)) { + var sortKeyListItem = this._parseSortKeyListItem(ber) + this._value.push(sortKeyListItem); + } + + if (this._value.length == 1) { + this._value = this._value[0]; + } return true; } @@ -114,4 +119,19 @@ ServerSideSortingControl.prototype._sortKeyListItemToBer = function(writer, obj) writer.endSequence(); }; +ServerSideSortingControl.prototype._parseSortKeyListItem = function(reader) { + var sortKeyListItem = {}; + sortKeyListItem.attributeType = reader.readString(asn1.Ber.OctetString); + + if (reader.peek() == 0x80) { + sortKeyListItem.orderingRule = reader.readString(0x80); + } + + if (reader.peek() == 0x81) { + sortKeyListItem.reverseOrder = (reader._readTag(0x81) === 0 ? false : true); + } + + return sortKeyListItem; +}; + ServerSideSortingControl.OID = '1.2.840.113556.1.4.473'; diff --git a/test/controls/server_side_sorting_control_test.js b/test/controls/server_side_sorting_control_test.js index 9cca748..dc28a75 100644 --- a/test/controls/server_side_sorting_control_test.js +++ b/test/controls/server_side_sorting_control_test.js @@ -8,11 +8,6 @@ var BerWriter = asn1.BerWriter; var getControl; var ServerSideSortingControl; -function bufferEqual(t, a, b) { - t.equal(a.toString('hex'), b.toString('hex')); -} - - ///--- Tests @@ -45,28 +40,18 @@ test('new with args', function (t) { t.ok(c.criticality); t.equal(c.value.attributeType, 'sn'); - var writer = new BerWriter(); - c.toBer(writer); - var reader = new BerReader(writer.buffer); - var sssc = getControl(reader); - t.ok(sssc); - console.log('sssc', sssc.value); - t.equal(sssc.type, '1.2.840.113556.1.4.473'); - t.ok(sssc.criticality); - t.equal(sssc.value.attributeType, 'sn'); - bufferEqual(t, sssc.value.cookie, new Buffer(['sn'])); - t.end(); }); -test('tober', function (t) { +test('tober - object', function (t) { var sssc = new ServerSideSortingControl({ type: '1.2.840.113556.1.4.473', criticality: true, value: { - attributeType: 'sn' - } - }); + attributeType: 'sn', + orderingRule: 'caseIgnoreOrderingMatch', + reverseOrder: true + }}); var ber = new BerWriter(); sssc.toBer(ber); @@ -76,7 +61,39 @@ test('tober', function (t) { t.equal(c.type, '1.2.840.113556.1.4.473'); t.ok(c.criticality); t.equal(c.value.attributeType, 'sn'); - bufferEqual(t, c.value.cookie, new Buffer(0)); + t.equal(c.value.orderingRule, 'caseIgnoreOrderingMatch'); + t.equal(c.value.reverseOrder, true); + + t.end(); +}); + +test('tober - array', function (t) { + var sssc = new ServerSideSortingControl({ + type: '1.2.840.113556.1.4.473', + criticality: true, + value: [{ + attributeType: 'sn', + orderingRule: 'caseIgnoreOrderingMatch', + reverseOrder: true + }, + { + attributeType: 'givenName', + orderingRule: 'caseIgnoreOrderingMatch' + }] + }); + + var ber = new BerWriter(); + sssc.toBer(ber); + + var c = getControl(new BerReader(ber.buffer)); + t.ok(c); + t.equal(c.type, '1.2.840.113556.1.4.473'); + t.ok(c.criticality); + t.equal(c.value[0].attributeType, 'sn'); + t.equal(c.value[0].orderingRule, 'caseIgnoreOrderingMatch'); + t.equal(c.value[0].reverseOrder, true); + t.equal(c.value[1].attributeType, 'givenName'); + t.equal(c.value[1].orderingRule, 'caseIgnoreOrderingMatch'); t.end(); }); From f1d4b667c3ba9cf5455892c5d78f5522faa87a06 Mon Sep 17 00:00:00 2001 From: Patrick Mooney <patrick.f.mooney@gmail.com> Date: Fri, 6 Jun 2014 17:23:27 -0500 Subject: [PATCH 4/6] Refactor ServerSideSortingControl - Fix lint errors - Always store SSSC sort fields as array - Rename test file to match 'make test' pattern --- lib/controls/server_side_sorting_control.js | 75 +++++++------------ ...js => server_side_sorting_control.test.js} | 54 +++++++------ 2 files changed, 58 insertions(+), 71 deletions(-) rename test/controls/{server_side_sorting_control_test.js => server_side_sorting_control.test.js} (63%) diff --git a/lib/controls/server_side_sorting_control.js b/lib/controls/server_side_sorting_control.js index 0f6308a..c55b6fa 100644 --- a/lib/controls/server_side_sorting_control.js +++ b/lib/controls/server_side_sorting_control.js @@ -13,7 +13,6 @@ var BerReader = asn1.BerReader; var BerWriter = asn1.BerWriter; - ///--- API function ServerSideSortingControl(options) { @@ -26,7 +25,7 @@ function ServerSideSortingControl(options) { this.parse(options.value); } else if (Array.isArray(options.value)) { for (var i = 0; i < options.value.length; i++) { - if (!typeof (options.value[i]) === 'object') { + if (typeof (options.value[i]) !== 'object') { throw new TypeError('Elements of options.value must be Objects'); } else if (!options.value[i].hasOwnProperty('attributeType')) { throw new Error('Missing required key: attributeType'); @@ -37,7 +36,7 @@ function ServerSideSortingControl(options) { if (!options.value.hasOwnProperty('attributeType')) { throw new Error('Missing required key: attributeType'); } - this._value = options.value; + this._value = [options.value]; } else { throw new TypeError('options.value must be a Buffer, Array or Object'); } @@ -47,7 +46,7 @@ function ServerSideSortingControl(options) { var self = this; this.__defineGetter__('value', function () { - return self._value || {}; + return self._value || []; }); } util.inherits(ServerSideSortingControl, Control); @@ -58,22 +57,23 @@ ServerSideSortingControl.prototype.parse = function parse(buffer) { assert.ok(buffer); var ber = new BerReader(buffer); - + var item; if (ber.readSequence(0x30)) { this._value = []; while (ber.readSequence(0x30)) { - var sortKeyListItem = this._parseSortKeyListItem(ber) - this._value.push(sortKeyListItem); + item = {}; + item.attributeType = ber.readString(asn1.Ber.OctetString); + if (ber.peek() == 0x80) { + item.orderingRule = ber.readString(0x80); + } + if (ber.peek() == 0x81) { + item.reverseOrder = (ber._readTag(0x81) === 0 ? false : true); + } + this._value.push(item); } - - if (this._value.length == 1) { - this._value = this._value[0]; - } - return true; } - return false; }; @@ -81,20 +81,25 @@ ServerSideSortingControl.prototype.parse = function parse(buffer) { ServerSideSortingControl.prototype._toBer = function (ber) { assert.ok(ber); - if (!this._value) + if (!this._value || this.value.length === 0) return; var writer = new BerWriter(); writer.startSequence(0x30); - - if (Array.isArray(this.value)) { - for (var i = 0; i < this.value.length; i++) { - this._sortKeyListItemToBer(writer, this.value[i]); + for (var i = 0; i < this.value.length; i++) { + var item = this.value[i]; + writer.startSequence(0x30); + if (item.attributeType) { + writer.writeString(item.attributeType, asn1.Ber.OctetString); } - } else if (typeof (this.value) === 'object') { - this._sortKeyListItemToBer(writer, this.value); + if (item.orderingRule) { + writer.writeString(item.orderingRule, 0x80); + } + if (item.reverseOrder) { + writer.writeBoolean(item.reverseOrder, 0x81); + } + writer.endSequence(); } - writer.endSequence(); ber.writeBuffer(writer.buffer, 0x04); }; @@ -105,33 +110,5 @@ ServerSideSortingControl.prototype._json = function (obj) { return obj; }; -ServerSideSortingControl.prototype._sortKeyListItemToBer = function(writer, obj) { - writer.startSequence(0x30); - if (obj.attributeType) { - writer.writeString(obj.attributeType, asn1.Ber.OctetString); - } - if (obj.orderingRule) { - writer.writeString(obj.orderingRule, 0x80); - } - if (obj.reverseOrder) { - writer.writeBoolean(obj.reverseOrder, 0x81); - } - writer.endSequence(); -}; - -ServerSideSortingControl.prototype._parseSortKeyListItem = function(reader) { - var sortKeyListItem = {}; - sortKeyListItem.attributeType = reader.readString(asn1.Ber.OctetString); - - if (reader.peek() == 0x80) { - sortKeyListItem.orderingRule = reader.readString(0x80); - } - - if (reader.peek() == 0x81) { - sortKeyListItem.reverseOrder = (reader._readTag(0x81) === 0 ? false : true); - } - - return sortKeyListItem; -}; ServerSideSortingControl.OID = '1.2.840.113556.1.4.473'; diff --git a/test/controls/server_side_sorting_control_test.js b/test/controls/server_side_sorting_control.test.js similarity index 63% rename from test/controls/server_side_sorting_control_test.js rename to test/controls/server_side_sorting_control.test.js index dc28a75..a144421 100644 --- a/test/controls/server_side_sorting_control_test.js +++ b/test/controls/server_side_sorting_control.test.js @@ -12,24 +12,20 @@ var ServerSideSortingControl; test('load library', function (t) { - ServerSideSortingControl = - require('../../lib').ServerSideSortingControl; + ServerSideSortingControl = require('../../lib').ServerSideSortingControl; t.ok(ServerSideSortingControl); getControl = require('../../lib').getControl; t.ok(getControl); t.end(); }); - test('new no args', function (t) { t.ok(new ServerSideSortingControl()); t.end(); }); - test('new with args', function (t) { var c = new ServerSideSortingControl({ - type: '1.2.840.113556.1.4.473', criticality: true, value: { attributeType: 'sn' @@ -38,14 +34,14 @@ test('new with args', function (t) { t.ok(c); t.equal(c.type, '1.2.840.113556.1.4.473'); t.ok(c.criticality); - t.equal(c.value.attributeType, 'sn'); + t.equal(c.value.length, 1); + t.equal(c.value[0].attributeType, 'sn'); t.end(); }); -test('tober - object', function (t) { +test('toBer - object', function (t) { var sssc = new ServerSideSortingControl({ - type: '1.2.840.113556.1.4.473', criticality: true, value: { attributeType: 'sn', @@ -60,26 +56,27 @@ test('tober - object', function (t) { t.ok(c); t.equal(c.type, '1.2.840.113556.1.4.473'); t.ok(c.criticality); - t.equal(c.value.attributeType, 'sn'); - t.equal(c.value.orderingRule, 'caseIgnoreOrderingMatch'); - t.equal(c.value.reverseOrder, true); + t.equal(c.value[0].attributeType, 'sn'); + t.equal(c.value[0].orderingRule, 'caseIgnoreOrderingMatch'); + t.equal(c.value[0].reverseOrder, true); t.end(); }); -test('tober - array', function (t) { +test('toBer - array', function (t) { var sssc = new ServerSideSortingControl({ - type: '1.2.840.113556.1.4.473', criticality: true, - value: [{ - attributeType: 'sn', - orderingRule: 'caseIgnoreOrderingMatch', - reverseOrder: true - }, - { - attributeType: 'givenName', - orderingRule: 'caseIgnoreOrderingMatch' - }] + value: [ + { + attributeType: 'sn', + orderingRule: 'caseIgnoreOrderingMatch', + reverseOrder: true + }, + { + attributeType: 'givenName', + orderingRule: 'caseIgnoreOrderingMatch' + } + ] }); var ber = new BerWriter(); @@ -89,6 +86,7 @@ test('tober - array', function (t) { t.ok(c); t.equal(c.type, '1.2.840.113556.1.4.473'); t.ok(c.criticality); + t.equal(c.value.length, 2); t.equal(c.value[0].attributeType, 'sn'); t.equal(c.value[0].orderingRule, 'caseIgnoreOrderingMatch'); t.equal(c.value[0].reverseOrder, true); @@ -97,3 +95,15 @@ test('tober - array', function (t) { t.end(); }); + +test('toBer - empty', function (t) { + var sssc = new ServerSideSortingControl(); + var ber = new BerWriter(); + sssc.toBer(ber); + + var c = getControl(new BerReader(ber.buffer)); + t.ok(c); + t.equal(c.type, '1.2.840.113556.1.4.473'); + t.equal(c.value.length, 0); + t.end(); +}); From 352e4bbfba5407034363d00ec69fa234b6f8fd45 Mon Sep 17 00:00:00 2001 From: Patrick Mooney <patrick.f.mooney@gmail.com> Date: Mon, 9 Jun 2014 15:37:19 -0700 Subject: [PATCH 5/6] Rename ServerSideSortingControl ServerSideSortingRequestControl will be more consistent when ServerSideSortingResponseControl is implemented. --- lib/controls/index.js | 9 +++++---- ...js => server_side_sorting_request_control.js} | 16 ++++++++-------- ... server_side_sorting_control_request.test.js} | 16 ++++++++-------- 3 files changed, 21 insertions(+), 20 deletions(-) rename lib/controls/{server_side_sorting_control.js => server_side_sorting_request_control.js} (83%) rename test/controls/{server_side_sorting_control.test.js => server_side_sorting_control_request.test.js} (85%) diff --git a/lib/controls/index.js b/lib/controls/index.js index 4157d5f..114e735 100644 --- a/lib/controls/index.js +++ b/lib/controls/index.js @@ -7,7 +7,8 @@ var EntryChangeNotificationControl = require('./entry_change_notification_control'); var PersistentSearchControl = require('./persistent_search_control'); var PagedResultsControl = require('./paged_results_control'); -var ServerSideSortingControl = require('./server_side_sorting_control.js'); +var ServerSideSortingRequestControl = + require('./server_side_sorting_request_control.js'); @@ -58,8 +59,8 @@ module.exports = { value: value }); break; - case ServerSideSortingControl.OID: - control = new ServerSideSortingControl({ + case ServerSideSortingRequestControl.OID: + control = new ServerSideSortingRequestControl({ critical: critical, value: value }); @@ -80,5 +81,5 @@ module.exports = { EntryChangeNotificationControl: EntryChangeNotificationControl, PagedResultsControl: PagedResultsControl, PersistentSearchControl: PersistentSearchControl, - ServerSideSortingControl: ServerSideSortingControl + ServerSideSortingRequestControl: ServerSideSortingRequestControl }; diff --git a/lib/controls/server_side_sorting_control.js b/lib/controls/server_side_sorting_request_control.js similarity index 83% rename from lib/controls/server_side_sorting_control.js rename to lib/controls/server_side_sorting_request_control.js index c55b6fa..4d2c6eb 100644 --- a/lib/controls/server_side_sorting_control.js +++ b/lib/controls/server_side_sorting_request_control.js @@ -15,11 +15,11 @@ var BerWriter = asn1.BerWriter; ///--- API -function ServerSideSortingControl(options) { +function ServerSideSortingRequestControl(options) { if (!options) options = {}; - options.type = ServerSideSortingControl.OID; + options.type = ServerSideSortingRequestControl.OID; if (options.value) { if (Buffer.isBuffer(options.value)) { this.parse(options.value); @@ -49,11 +49,11 @@ function ServerSideSortingControl(options) { return self._value || []; }); } -util.inherits(ServerSideSortingControl, Control); -module.exports = ServerSideSortingControl; +util.inherits(ServerSideSortingRequestControl, Control); +module.exports = ServerSideSortingRequestControl; -ServerSideSortingControl.prototype.parse = function parse(buffer) { +ServerSideSortingRequestControl.prototype.parse = function parse(buffer) { assert.ok(buffer); var ber = new BerReader(buffer); @@ -78,7 +78,7 @@ ServerSideSortingControl.prototype.parse = function parse(buffer) { }; -ServerSideSortingControl.prototype._toBer = function (ber) { +ServerSideSortingRequestControl.prototype._toBer = function (ber) { assert.ok(ber); if (!this._value || this.value.length === 0) @@ -105,10 +105,10 @@ ServerSideSortingControl.prototype._toBer = function (ber) { }; -ServerSideSortingControl.prototype._json = function (obj) { +ServerSideSortingRequestControl.prototype._json = function (obj) { obj.controlValue = this.value; return obj; }; -ServerSideSortingControl.OID = '1.2.840.113556.1.4.473'; +ServerSideSortingRequestControl.OID = '1.2.840.113556.1.4.473'; diff --git a/test/controls/server_side_sorting_control.test.js b/test/controls/server_side_sorting_control_request.test.js similarity index 85% rename from test/controls/server_side_sorting_control.test.js rename to test/controls/server_side_sorting_control_request.test.js index a144421..e2787dd 100644 --- a/test/controls/server_side_sorting_control.test.js +++ b/test/controls/server_side_sorting_control_request.test.js @@ -6,26 +6,26 @@ var asn1 = require('asn1'); var BerReader = asn1.BerReader; var BerWriter = asn1.BerWriter; var getControl; -var ServerSideSortingControl; +var SSSRControl; ///--- Tests test('load library', function (t) { - ServerSideSortingControl = require('../../lib').ServerSideSortingControl; - t.ok(ServerSideSortingControl); + SSSRControl = require('../../lib').ServerSideSortingRequestControl; + t.ok(SSSRControl); getControl = require('../../lib').getControl; t.ok(getControl); t.end(); }); test('new no args', function (t) { - t.ok(new ServerSideSortingControl()); + t.ok(new SSSRControl()); t.end(); }); test('new with args', function (t) { - var c = new ServerSideSortingControl({ + var c = new SSSRControl({ criticality: true, value: { attributeType: 'sn' @@ -41,7 +41,7 @@ test('new with args', function (t) { }); test('toBer - object', function (t) { - var sssc = new ServerSideSortingControl({ + var sssc = new SSSRControl({ criticality: true, value: { attributeType: 'sn', @@ -64,7 +64,7 @@ test('toBer - object', function (t) { }); test('toBer - array', function (t) { - var sssc = new ServerSideSortingControl({ + var sssc = new SSSRControl({ criticality: true, value: [ { @@ -97,7 +97,7 @@ test('toBer - array', function (t) { }); test('toBer - empty', function (t) { - var sssc = new ServerSideSortingControl(); + var sssc = new SSSRControl(); var ber = new BerWriter(); sssc.toBer(ber); From e8593f78ce50ba9052b140a2cb9d0222dd06b22b Mon Sep 17 00:00:00 2001 From: Patrick Mooney <patrick.f.mooney@gmail.com> Date: Mon, 9 Jun 2014 15:58:01 -0700 Subject: [PATCH 6/6] Add ServerSideSortingResponseControl --- lib/controls/index.js | 11 +- .../server_side_sorting_response_control.js | 105 ++++++++++++++++ ...rver_side_sorting_control_response.test.js | 117 ++++++++++++++++++ 3 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 lib/controls/server_side_sorting_response_control.js create mode 100644 test/controls/server_side_sorting_control_response.test.js diff --git a/lib/controls/index.js b/lib/controls/index.js index 114e735..94f311a 100644 --- a/lib/controls/index.js +++ b/lib/controls/index.js @@ -9,6 +9,8 @@ var PersistentSearchControl = require('./persistent_search_control'); var PagedResultsControl = require('./paged_results_control'); var ServerSideSortingRequestControl = require('./server_side_sorting_request_control.js'); +var ServerSideSortingResponseControl = + require('./server_side_sorting_response_control.js'); @@ -65,6 +67,12 @@ module.exports = { value: value }); break; + case ServerSideSortingResponseControl.OID: + control = new ServerSideSortingResponseControl({ + critical: critical, + value: value + }); + break; default: control = new Control({ type: type, @@ -81,5 +89,6 @@ module.exports = { EntryChangeNotificationControl: EntryChangeNotificationControl, PagedResultsControl: PagedResultsControl, PersistentSearchControl: PersistentSearchControl, - ServerSideSortingRequestControl: ServerSideSortingRequestControl + ServerSideSortingRequestControl: ServerSideSortingRequestControl, + ServerSideSortingResponseControl: ServerSideSortingResponseControl }; diff --git a/lib/controls/server_side_sorting_response_control.js b/lib/controls/server_side_sorting_response_control.js new file mode 100644 index 0000000..9ac2a67 --- /dev/null +++ b/lib/controls/server_side_sorting_response_control.js @@ -0,0 +1,105 @@ +var assert = require('assert'); +var util = require('util'); + +var asn1 = require('asn1'); + +var Control = require('./control'); + +var CODES = require('../errors/index'); + + + +///--- Globals + +var BerReader = asn1.BerReader; +var BerWriter = asn1.BerWriter; + +var VALID_CODES = [ + CODES.LDAP_SUCCESS, + CODES.LDAP_OPERATIONS_ERROR, + CODES.LDAP_TIME_LIMIT_EXCEEDED, + CODES.LDAP_STRONG_AUTH_REQUIRED, + CODES.LDAP_ADMIN_LIMIT_EXCEEDED, + CODES.LDAP_NO_SUCH_ATTRIBUTE, + CODES.LDAP_INAPPROPRIATE_MATCHING, + CODES.LDAP_INSUFFICIENT_ACCESS_RIGHTS, + CODES.LDAP_BUSY, + CODES.LDAP_UNWILLING_TO_PERFORM, + CODES.LDAP_OTHER +]; + +function ServerSideSortingResponseControl(options) { + if (!options) + options = {}; + + options.type = ServerSideSortingResponseControl.OID; + options.criticality = false; + + if (options.value) { + if (Buffer.isBuffer(options.value)) { + this.parse(options.value); + } else if (typeof (options.value) === 'object') { + if (VALID_CODES.indexOf(options.value.result) === -1) { + throw new Error('Invalid result code'); + } + if (options.value.failedAttribute && + typeof (options.value.failedAttribute) !== 'string') { + throw new Error('failedAttribute must be String'); + } + + this._value = options.value; + } else { + throw new TypeError('options.value must be a Buffer or Object'); + } + options.value = null; + } + Control.call(this, options); + + var self = this; + this.__defineGetter__('value', function () { + return self._value || {}; + }); +} +util.inherits(ServerSideSortingResponseControl, Control); +module.exports = ServerSideSortingResponseControl; + + +ServerSideSortingResponseControl.prototype.parse = function parse(buffer) { + assert.ok(buffer); + + var ber = new BerReader(buffer); + if (ber.readSequence(0x30)) { + this._value = {}; + this._value.result = ber.readEnumeration(); + if (ber.peek() == 0x80) { + this._value.failedAttribute = ber.readString(0x80); + } + return true; + } + return false; +}; + + +ServerSideSortingResponseControl.prototype._toBer = function (ber) { + assert.ok(ber); + + if (!this._value || this.value.length === 0) + return; + + var writer = new BerWriter(); + writer.startSequence(0x30); + writer.writeEnumeration(this.value.result); + if (this.value.result !== CODES.LDAP_SUCCESS && this.value.failedAttribute) { + writer.writeString(this.value.failedAttribute, 0x80); + } + writer.endSequence(); + ber.writeBuffer(writer.buffer, 0x04); +}; + + +ServerSideSortingResponseControl.prototype._json = function (obj) { + obj.controlValue = this.value; + return obj; +}; + +ServerSideSortingResponseControl.OID = '1.2.840.113556.1.4.474'; diff --git a/test/controls/server_side_sorting_control_response.test.js b/test/controls/server_side_sorting_control_response.test.js new file mode 100644 index 0000000..432edb7 --- /dev/null +++ b/test/controls/server_side_sorting_control_response.test.js @@ -0,0 +1,117 @@ +var test = require('tap').test; + +var asn1 = require('asn1'); + +var BerReader = asn1.BerReader; +var BerWriter = asn1.BerWriter; +var ldap; +var getControl; +var SSSResponseControl; +var OID = '1.2.840.113556.1.4.474'; + +///--- Tests + + +test('load library', function (t) { + ldap = require('../../lib'); + SSSResponseControl = ldap.ServerSideSortingResponseControl; + t.ok(SSSResponseControl); + getControl = ldap.getControl; + t.ok(getControl); + t.end(); +}); + +test('new no args', function (t) { + var c = new SSSResponseControl(); + t.ok(c); + t.equal(c.type, OID); + t.equal(c.criticality, false); + t.end(); +}); + +test('new with args', function (t) { + var c = new SSSResponseControl({ + criticality: true, + value: { + result: ldap.LDAP_SUCCESS, + failedAttribute: 'cn' + } + }); + t.ok(c); + t.equal(c.type, OID); + t.equal(c.criticality, false); + t.equal(c.value.result, ldap.LDAP_SUCCESS); + t.equal(c.value.failedAttribute, 'cn'); + + t.end(); +}); + +test('toBer - success', function (t) { + var sssc = new SSSResponseControl({ + value: { + result: ldap.LDAP_SUCCESS, + failedAttribute: 'foobar' + }}); + + var ber = new BerWriter(); + sssc.toBer(ber); + + var c = getControl(new BerReader(ber.buffer)); + t.ok(c); + t.equal(c.type, '1.2.840.113556.1.4.474'); + t.equal(c.criticality, false); + t.equal(c.value.result, ldap.LDAP_SUCCESS); + t.notOk(c.value.failedAttribute); + t.end(); +}); + +test('toBer - simple failure', function (t) { + var sssc = new SSSResponseControl({ + value: { + result: ldap.LDAP_NO_SUCH_ATTRIBUTE + }}); + + var ber = new BerWriter(); + sssc.toBer(ber); + + var c = getControl(new BerReader(ber.buffer)); + t.ok(c); + t.equal(c.type, OID); + t.equal(c.criticality, false); + t.equal(c.value.result, ldap.LDAP_NO_SUCH_ATTRIBUTE); + t.notOk(c.value.failedAttribute); + t.end(); +}); + +test('toBer - detailed failure', function (t) { + var sssc = new SSSResponseControl({ + value: { + result: ldap.LDAP_NO_SUCH_ATTRIBUTE, + failedAttribute: 'foobar' + }}); + + var ber = new BerWriter(); + sssc.toBer(ber); + + var c = getControl(new BerReader(ber.buffer)); + t.ok(c); + t.equal(c.type, OID); + t.equal(c.criticality, false); + t.equal(c.value.result, ldap.LDAP_NO_SUCH_ATTRIBUTE); + t.equal(c.value.failedAttribute, 'foobar'); + t.end(); +}); + +test('toBer - empty', function (t) { + var sssc = new SSSResponseControl(); + var ber = new BerWriter(); + sssc.toBer(ber); + + var c = getControl(new BerReader(ber.buffer)); + t.ok(c); + t.equal(c.type, OID); + t.equal(c.criticality, false); + t.notOk(c.value.result); + t.notOk(c.value.failedAttribute); + t.end(); +});