Author: Téo Pisenti ([email protected])
Simple (< 1000loc) LDAP client using modern ocaml frameworks:
- Asn1-combinators for parsing LDAP grammar
- EIO for networking and tasks synchronization
The current status supports following operations of the LDAP v3 RFC:
- binding/unbinding to an LDAP user
- search operations
The provided program in bin/main.ml show the library features by doing an example of authenticated search in a public demonstrational LDAP server: https://www.forumsys.com/2022/05/10/online-ldap-test-server/
Note
This project needs the patch 0001-report-Eof-as-a-distinct-error.patch to be applied to asn1-combinators sources to build. This requirement is automatically handled if you use nix-shell. See mirleft/ocaml-asn1-combinators#46 for more.
- Install dependencies:
opam install . --deps-only - Build project with dune:
dune build && dune install
The client binary takes no argument as demonstration queries are hard coded in bin/main.ml.
NB: If you use nix, you can open the development environment with nix-shell.
bin/main.ml: program to present lib usagelib/messages.ml: LDAP messages parsers using asn1-combinatorslib/conn.ml: LDAP TCP connection management and synchronization using EIO
Communication with the LDAP server is done through a TCP socket. In lib/conn.ml, multiple Eio.Fiber.t are used to manage this socket for both performance and synchronization reasons (see previous picture).
The client sends requests with an integer "messageId" and all responses in that transaction will use the same "messageId". Multiple unrelated transactions can occur simultaneously, so the "messageId" of each server response must be checked.
In this design, each concurrent transaction must be done through a single "client Fiber".
The "client Fiber" communicates with the "control Fiber" whose role is to forward only the LDAP messages from/to "client Fibers"
This communication is handled by the "control Stream", which is an Eio.Stream.t.
The "control Fiber" automatically forwards a response from the LDAP server to the correct "client Fiber" that initiate the LDAP request. This ensure the code inside the "client Fiber" is fully synchronous and see only relevant messages.
The lifetime of a "client Fiber" is as follows:
- The "client Fiber" subscribes to the "control Fiber" by sending a new
Eio.Stream.tto the "control Stream" - The "control Fiber" assign a new "messageId" to this subscription and save the stream in the "subs"
Map.t. - The "control Fiber" sends the assigned messageId through the given
Eio.Stream.tso the "client Fiber" can use it in all following messages - The "client Fiber" sends its LDAP request message with the correct "messageId" by adding it to the "control Stream"
- When a LDAP response is received by the "receiver Fiber" on the "control Stream", the "control Fiber" looks in the "subs"
Map.tto forward the message to theEio.Stream.tof the correct "client Fiber" - When finished, a "client Fiber" must unsubscribe by adding the
Unsubmessage to the "control Stream"
For conveniance, the send_0_response; send_1_response and send_fold_response functions are given, so you don't need to rewrite the "client Fiber" logic in your LDAP client. See bin/main.ml for example.
