Skip to content
This repository has been archived by the owner on May 14, 2024. It is now read-only.

Support for SyncRequestControl #952

Open
its-sami opened this issue Nov 9, 2023 · 1 comment
Open

Support for SyncRequestControl #952

its-sami opened this issue Nov 9, 2023 · 1 comment

Comments

@its-sami
Copy link
Contributor

its-sami commented Nov 9, 2023

I'd like to use a Sync Operation as defined here, which provides similar functionality to a persistent search but is supported by OpenLDAP.

Currently, the client fails after the initial response from the server with error IntermediateResponse. What would it take to support this operation, and are there any plans to do so?

I'm using ldapjs v3.0.4

Example code:

const client = ldap.createClient({
  url: bindURL,
});

client.bind(bindDN, bindPassword, (err) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log('bind success');

  client.search(searchDN, {scope: 'base'}, new SyncRequestControl({value: {mode: 3}}), (err, res) => {
    if (err) {
      console.error(err);
      return;
    }

    res.on('searchRequest', ({ messageId, protocolOp, controls }) => {
      console.log(`searchRequest: messageId=${messageId}, protocolOp=${protocolOp}, controls=${controls.map(c => c.type)}`);
    });
    res.on('searchEntry', ({messageID, protocolOp, controls}) => {
      console.log(`entry: messageId=${messageID}, protocolOp=${protocolOp}, controls=${controls.map(c => c.type)}`);
    });
    res.on('searchReference', (referral) => {
      console.log('referral: ' + referral.uris.join());
    });
    res.on('error', (err) => {
      console.error(`error: ${err.name}, ${err.message}, [${err.code}]`);
      client.unbind();
    });
    res.on('end', (result) => {
      console.log('status: ' + result.status);
      client.unbind((err) => {
        if (err) {
          console.error(err);
          return;
        }
        console.log('unbind success');
      });
    });
  });
});

class SyncRequestControl extends Control {
  static OID = '1.3.6.1.4.1.4203.1.9.1.1';

  _value: any;

  constructor(options: any = {}) {
    options.type = SyncRequestControl.OID;
    super(options);

    if (!options.value) {
      return;
    }

    if (typeof options.value === 'object') {
      this._value = options.value;
    } else {
      // TODO check if actually a buffer
      this.parse(options.value);
    }
  }

  get value() {
    return this._value;
  }

  set value(value) {
    this._value = {...value};
  }

  private parse(ber: Buffer) {
    throw new Error('Not implemented');
  }

  _toBer (ber) {
    const writer = new BerWriter();

    writer.startSequence();
    writer.writeInt(this._value.mode, 0x0a);
    writer.endSequence();

    ber.writeBuffer(writer.buffer, 0x04)
    return ber
  }
}

Example output

> bind success
> searchRequest: messageId=2, protocolOp=99, controls=1.3.6.1.4.1.4203.1.9.1.1
> entry: messageId=2, protocolOp=100, controls=1.3.6.1.4.1.4203.1.9.1.2
> error: ProtocolError, IntermediateResponse, [2]
@jsumners
Copy link
Member

jsumners commented Nov 9, 2023

What I can say based upon your findings is that you're getting a message back from the server that is hitting the branch https://github.com/ldapjs/messages/blob/b73f34bc3769210af4b5805ef8d06c89d3e456ca/lib/parse-to-message.js#L198

This meshes with the RFC you linked. See https://www.rfc-editor.org/rfc/rfc4533#section-2.5

Thus, there will need to be some work done to recognize the message and handle it correctly. This is noted in https://github.com/ldapjs/messages/blob/b73f34bc3769210af4b5805ef8d06c89d3e456ca/lib/messages/intermediate-response.js#L26-L36

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants