Files
ldap-to-oauth2/node_modules/@ldapjs/messages/lib/ldap-result.test.js
2025-10-08 11:12:59 -04:00

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.'
})
})
})