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(); +});