284 lines
7.3 KiB
JavaScript
284 lines
7.3 KiB
JavaScript
'use strict'
|
|
|
|
const tap = require('tap')
|
|
const warning = require('./deprecations')
|
|
const { resultCodes, operations } = require('@ldapjs/protocol')
|
|
const { BerReader } = require('@ldapjs/asn1')
|
|
const {
|
|
addResponseBasicBytes,
|
|
addResponseNoSuchObjectBytes,
|
|
addResponseReferralsBytes,
|
|
extensionDisconnectionNotificationResponseBytes
|
|
} = require('./messages/_fixtures/message-byte-arrays')
|
|
const RECOGNIZED_OIDS = require('./messages/extension-utils/recognized-oids')
|
|
const LdapResult = require('./ldap-result')
|
|
const ExtensionResponse = require('./messages/extension-response')
|
|
|
|
// Silence the standard warning logs. We will test the messages explicitly.
|
|
process.removeAllListeners('warning')
|
|
|
|
tap.test('constructor', t => {
|
|
t.test('no args', async t => {
|
|
const res = new LdapResult()
|
|
t.equal(res.status, 0)
|
|
t.equal(res.matchedDN, '')
|
|
t.strictSame(res.referrals, [])
|
|
t.equal(res.diagnosticMessage, '')
|
|
})
|
|
|
|
t.test('emits warning for abandonID', t => {
|
|
process.on('warning', handler)
|
|
t.teardown(async () => {
|
|
process.removeListener('warning', handler)
|
|
warning.emitted.set('LDAP_MESSAGE_DEP_004', false)
|
|
})
|
|
|
|
const res = new LdapResult({
|
|
errorMessage: 'foo'
|
|
})
|
|
t.ok(res)
|
|
|
|
function handler (error) {
|
|
t.equal(
|
|
error.message,
|
|
'errorMessage is deprecated. Use diagnosticMessage instead.'
|
|
)
|
|
t.end()
|
|
}
|
|
})
|
|
|
|
t.test('with options', async t => {
|
|
const res = new LdapResult({
|
|
status: 1,
|
|
matchedDN: 'foo',
|
|
referrals: ['foo.example.com'],
|
|
diagnosticMessage: 'bar'
|
|
})
|
|
t.equal(res.status, 1)
|
|
t.equal(res.matchedDN, 'foo')
|
|
t.strictSame(res.referrals, ['foo.example.com'])
|
|
t.equal(res.diagnosticMessage, 'bar')
|
|
})
|
|
|
|
t.end()
|
|
})
|
|
|
|
tap.test('.diagnosticMessage', t => {
|
|
t.test('sets and gets', async t => {
|
|
const res = new LdapResult()
|
|
t.equal(res.diagnosticMessage, '')
|
|
res.diagnosticMessage = 'foo'
|
|
t.equal(res.diagnosticMessage, 'foo')
|
|
})
|
|
|
|
t.end()
|
|
})
|
|
|
|
tap.test('.matchedDN', t => {
|
|
t.test('sets and gets', async t => {
|
|
const res = new LdapResult()
|
|
t.equal(res.matchedDN, '')
|
|
res.matchedDN = 'foo'
|
|
t.equal(res.matchedDN, 'foo')
|
|
})
|
|
|
|
t.end()
|
|
})
|
|
|
|
tap.test('.pojo', t => {
|
|
t.test('returns a plain JavaScript object', async t => {
|
|
const res = new LdapResult()
|
|
t.strictSame(res.pojo, {
|
|
status: 0,
|
|
matchedDN: '',
|
|
diagnosticMessage: '',
|
|
referrals: []
|
|
})
|
|
})
|
|
|
|
t.test('returns a plain JavaScript object from subclass', async t => {
|
|
class Foo extends LdapResult {
|
|
_pojo (obj) {
|
|
obj.foo = 'foo'
|
|
return obj
|
|
}
|
|
}
|
|
|
|
const res = new Foo()
|
|
t.strictSame(res.pojo, {
|
|
status: 0,
|
|
matchedDN: '',
|
|
diagnosticMessage: '',
|
|
referrals: [],
|
|
foo: 'foo'
|
|
})
|
|
})
|
|
|
|
t.end()
|
|
})
|
|
|
|
tap.test('.referrals', t => {
|
|
t.test('gets', async t => {
|
|
const res = new LdapResult({ referrals: ['foo'] })
|
|
t.strictSame(res.referrals, ['foo'])
|
|
})
|
|
|
|
t.end()
|
|
})
|
|
|
|
tap.test('.status', t => {
|
|
t.test('sets and gets', async t => {
|
|
const res = new LdapResult()
|
|
t.equal(res.status, 0)
|
|
res.status = 1
|
|
t.equal(res.status, 1)
|
|
})
|
|
|
|
t.end()
|
|
})
|
|
|
|
tap.test('.type', t => {
|
|
t.test('gets', async t => {
|
|
const res = new LdapResult()
|
|
t.equal(res.type, 'LdapResult')
|
|
})
|
|
|
|
t.end()
|
|
})
|
|
|
|
tap.test('addReferral', t => {
|
|
t.test('adds to existing list', async t => {
|
|
const res = new LdapResult({ referrals: ['foo'] })
|
|
t.strictSame(res.referrals, ['foo'])
|
|
res.addReferral('bar')
|
|
t.strictSame(res.referrals, ['foo', 'bar'])
|
|
})
|
|
|
|
t.end()
|
|
})
|
|
|
|
tap.test('_toBer', t => {
|
|
t.test('returns basic bytes', async t => {
|
|
const res = new LdapResult({
|
|
protocolOp: operations.LDAP_RES_ADD,
|
|
messageId: 2
|
|
})
|
|
const ber = res.toBer()
|
|
const expected = Buffer.from(addResponseBasicBytes)
|
|
t.equal(expected.compare(ber.buffer), 0)
|
|
})
|
|
|
|
t.test('returns bytes with referrals', async t => {
|
|
const res = new LdapResult({
|
|
protocolOp: operations.LDAP_RES_ADD,
|
|
messageId: 3,
|
|
status: resultCodes.REFERRAL,
|
|
diagnosticMessage: 'This server is read-only. Try a different one.',
|
|
referrals: [
|
|
'ldap://alternate1.example.com:389/uid=jdoe,ou=Remote,dc=example,dc=com',
|
|
'ldap://alternate2.example.com:389/uid=jdoe,ou=Remote,dc=example,dc=com'
|
|
]
|
|
})
|
|
const ber = res.toBer()
|
|
const expected = Buffer.from(addResponseReferralsBytes)
|
|
t.equal(expected.compare(ber.buffer), 0)
|
|
})
|
|
|
|
t.test('hands off to _writeResponse', async t => {
|
|
const res = new ExtensionResponse({
|
|
protocolOp: operations.LDAP_RES_EXTENSION,
|
|
messageId: 0,
|
|
status: resultCodes.UNAVAILABLE,
|
|
diagnosticMessage: 'The Directory Server is shutting down',
|
|
referrals: [],
|
|
responseName: RECOGNIZED_OIDS.get('DISCONNECTION_NOTIFICATION')
|
|
})
|
|
const ber = res.toBer()
|
|
const expected = Buffer.from(extensionDisconnectionNotificationResponseBytes)
|
|
t.equal(expected.compare(ber.buffer), 0)
|
|
})
|
|
|
|
t.end()
|
|
})
|
|
|
|
tap.test('#parseToPojo', t => {
|
|
t.test('throws because not implemented', async t => {
|
|
const expected = Error('Use LdapMessage.parse, or a specific message type\'s parseToPojo, instead.')
|
|
t.throws(
|
|
() => LdapResult.parseToPojo(),
|
|
expected
|
|
)
|
|
})
|
|
|
|
t.end()
|
|
})
|
|
|
|
tap.test('#_parseToPojo', async t => {
|
|
t.test('throws if protocol op is wrong', async t => {
|
|
const bytes = addResponseBasicBytes.slice(5)
|
|
bytes[0] = 0x68
|
|
const berReader = new BerReader(Buffer.from(bytes))
|
|
t.throws(
|
|
() => LdapResult._parseToPojo({
|
|
opCode: operations.LDAP_RES_ADD,
|
|
berReader
|
|
}),
|
|
Error('found wrong protocol operation: 0x68')
|
|
)
|
|
})
|
|
|
|
t.test('parses a basic object', async t => {
|
|
const bytes = addResponseBasicBytes.slice(5)
|
|
const berReader = new BerReader(Buffer.from(bytes))
|
|
const pojo = { foo: 'foo' }
|
|
LdapResult._parseToPojo({
|
|
opCode: operations.LDAP_RES_ADD,
|
|
berReader,
|
|
pojo
|
|
})
|
|
t.strictSame(pojo, {
|
|
status: 0,
|
|
matchedDN: '',
|
|
diagnosticMessage: '',
|
|
referrals: [],
|
|
foo: 'foo'
|
|
})
|
|
})
|
|
|
|
t.test('parses object with matched dn and diagnostic message', async t => {
|
|
const bytes = addResponseNoSuchObjectBytes.slice(6)
|
|
const berReader = new BerReader(Buffer.from(bytes))
|
|
const pojo = LdapResult._parseToPojo({
|
|
opCode: operations.LDAP_RES_ADD,
|
|
berReader
|
|
})
|
|
t.strictSame(pojo, {
|
|
status: resultCodes.NO_SUCH_OBJECT,
|
|
referrals: [],
|
|
matchedDN: 'ou=People, dc=example, dc=com',
|
|
diagnosticMessage: [
|
|
'Entry uid=missing1, ou=missing2, ou=People, dc=example, dc=com cannot',
|
|
' be created because its parent does not exist.'
|
|
].join('')
|
|
})
|
|
})
|
|
|
|
t.test('parses object with referrals', async t => {
|
|
const bytes = addResponseReferralsBytes.slice(6)
|
|
const berReader = new BerReader(Buffer.from(bytes))
|
|
const pojo = LdapResult._parseToPojo({
|
|
opCode: operations.LDAP_RES_ADD,
|
|
berReader
|
|
})
|
|
t.strictSame(pojo, {
|
|
status: resultCodes.REFERRAL,
|
|
referrals: [
|
|
'ldap://alternate1.example.com:389/uid=jdoe,ou=Remote,dc=example,dc=com',
|
|
'ldap://alternate2.example.com:389/uid=jdoe,ou=Remote,dc=example,dc=com'
|
|
],
|
|
matchedDN: '',
|
|
diagnosticMessage: 'This server is read-only. Try a different one.'
|
|
})
|
|
})
|
|
})
|