RFC 4533

The Lightweight Directory Access Protocol (LDAP) Content Synchronization Operation

πŸ“… published June 2006, from ietf

RFC 4533: The Lightweight Directory Access Protocol (LDAP) Content Synchronization Operation πŸ¦‹

okay so this one's RFC 4533 πŸ’– and it's from the Network Working Group, dated June 2006. The authors are K. Zeilenga of the OpenLDAP Foundation and J.H. Choi of IBM Corporation 🫢. It's in the Experimental category πŸ§ͺ, and the title block doesn't list anything it obsoletes or updates, so it's just doing its own thing ✨.


Status of This Memo πŸ“‹

bestie, this memo defines an Experimental Protocol for the Internet community πŸ§ͺ. It does not specify an Internet standard of any kind, so don't go treating it like one πŸ™ˆ. They're asking for discussion and suggestions for improvement, and distribution of this memo is unlimited πŸ’œ.

Copyright (C) The Internet Society (2006).

IESG Note πŸ“

the IESG wanted to flag something here πŸ‘€. This work was originally discussed in the LDUP working group, but the group landed on a different approach, documented in RFC 3928. That one is on the standards track πŸ‘‘, so if you're thinking about implementing this proposal, you should go read it too 🫢.

Abstract 🌸

this spec describes the Lightweight Directory Access Protocol (LDAP) Content Synchronization Operation, or the Sync Operation ✨. It lets a client keep a copy of a fragment of the Directory Information Tree (DIT) 🌳. It supports both polling for changes and listening for changes, and it's defined as an extension of the LDAP Search Operation πŸ”.

Table of Contents πŸ—‚οΈ

   1. Introduction ....................................................3
      1.1. Background .................................................3
      1.2. Intended Usage .............................................4
      1.3. Overview ...................................................5
      1.4. Conventions ................................................8
   2. Elements of the Sync Operation ..................................8
      2.1. Common ASN.1 Elements ......................................9
      2.2. Sync Request Control .......................................9
      2.3. Sync State Control ........................................10
      2.4. Sync Done Control .........................................10
      2.5. Sync Info Message .........................................11
      2.6. Sync Result Codes .........................................11
   3. Content Synchronization ........................................11
      3.1. Synchronization Session ...................................12
      3.2. Content Determination .....................................12
      3.3. refreshOnly Mode ..........................................13
      3.4. refreshAndPersist Mode ....................................16
      3.5. Search Request Parameters .................................17
      3.6. objectName ................................................18
      3.7. Canceling the Sync Operation ..............................19
      3.8. Refresh Required ..........................................19
      3.9. Chattiness Considerations .................................20
      3.10. Operation Multiplexing ...................................21
   4. Meta Information Considerations ................................22
      4.1. Entry DN ..................................................22
      4.2. Operational Attributes ....................................22
      4.3. Collective Attributes .....................................23
      4.4. Access and Other Administrative Controls ..................23
   5. Interaction with Other Controls ................................23
      5.1. ManageDsaIT Control .......................................24
      5.2. Subentries Control ........................................24
   6. Shadowing Considerations .......................................24
   7. Security Considerations ........................................25
   8. IANA Considerations ............................................26
      8.1. Object Identifier .........................................26
      8.2. LDAP Protocol Mechanism ...................................26
      8.3. LDAP Result Codes .........................................26
   9. Acknowledgements ...............................................26
   10. Normative References ..........................................27
   11. Informative References ........................................28
   Appendix A.  CSN-based Implementation Considerations ..............29

1. Introduction πŸŽ€

okay so LDAP [RFC4510] has a search operation [RFC4511] that lets a client ask for directory content matching a complicated set of assertions πŸ”. The server then sends that content back, subject to access control and other restrictions πŸ”. But here's the tea πŸ«–: even with a ton of extensions over the years, LDAP still doesn't have an effective and efficient way to keep synchronized copies of directory content 😭. This document introduces a brand-new mechanism built for the content synchronization needs of sophisticated directory apps πŸ’….

this doc defines the LDAP Content Synchronization Operation, or Sync Operation for short ✨. It lets a client keep a synchronized copy of a fragment of a Directory Information Tree (DIT) 🌳. The Sync Operation is a set of controls and other protocol elements that extend the Search Operation, so it's built right on top of what LDAP already does 🧱.

1.1. Background πŸ“š

a bunch of content synchronization approaches have been floated for LDAP directory services over the years πŸ•°οΈ. Honestly, they fell short for one or more of these reasons:

  • failure to ensure a reasonable level of convergence;
  • failure to detect that convergence cannot be achieved (without reload);
  • require pre-arranged synchronization agreements;
  • require the server to maintain histories of past changes to DIT content and/or meta information;
  • require the server to maintain synchronization state on a per-client basis; and/or
  • are overly chatty.

so the Sync Operation gives you eventual convergence of synchronized content when it's possible 🎯. When it isn't, the client gets a notification that a full reload is required πŸ”„.

the Sync Operation does not need pre-arranged synchronization agreements 🀝. It also doesn't require that servers maintain or use any history of past changes to the DIT or to meta information πŸ™…β€β™€οΈ. That said, servers may maintain and use histories (e.g., change logs, tombstones, DIT snapshots) to cut down on the number of messages and how big they are πŸ“‰. Since it's not always feasible to keep and use histories, the operation may be implemented using purely (current) state-based approaches πŸ§˜β€β™€οΈ. The Sync Operation lets you use either the state-based approach or the history-based approach on an operation-by-operation basis, so you can balance the size of history against the amount of traffic βš–οΈ. It also allows the combined use of the state-based and the history-based approaches πŸ’œ.

the Sync Operation doesn't require that servers keep synchronization state on a per-client basis πŸ™Œ. Servers may maintain and use per-client state information to reduce the number of messages generated and the size of those messages πŸ“¦.

a synchronization mechanism counts as overly chatty when its synchronization traffic isn't reasonably bounded πŸ—£οΈπŸ’€. The Sync Operation traffic is bounded by the size of updated (or new) entries and the number of unchanged entries in the content πŸŽ€. The operation is designed to avoid full content exchanges, even when the server's history info isn't enough to figure out the client's state πŸ™…β€β™€οΈ. It's also designed to avoid sending out-of-content history information. Its size isn't bounded by the content, and it isn't always feasible to transmit it due to security reasons πŸ”’.

this document includes a number of non-normative appendices that give extra info to server implementors πŸ› οΈ.

1.2. Intended Usage 🎯

the Sync Operation is meant for applications that need eventually-convergent content synchronization πŸ’–. When each synchronization stage of the operation finishes, all the info needed to build a synchronized client copy has either been given to the client, or the client has been told that a complete content reload is necessary πŸ“¬. Apart from transient inconsistencies from concurrent operation (or other) processing at the server, the client copy accurately reflects what the server holds ✨. Those transient inconsistencies get resolved by later synchronization operations πŸ”.

possible uses include:

  • White page service applications may use the Sync Operation to maintain a current copy of a DIT fragment, for example, a mail user agent that uses the sync operation to maintain a local copy of an enterprise address book. πŸ“‡
  • Meta-information engines may use the Sync Operation to maintain a copy of a DIT fragment. 🧠
  • Caching proxy services may use the Sync Operation to maintain a coherent content cache. πŸ—„οΈ
  • Lightweight master-slave replication between heterogeneous directory servers. For example, the Sync Operation can be used by a slave server to maintain a shadow copy of a DIT fragment. (Note: The International Telephone Union (ITU) has defined the X.500 Directory [X.500] Information Shadowing Protocol (DISP) [X.525], which may be used for master-slave replication between directory servers. Other experimental LDAP replication protocols also exist.) πŸͺž

this protocol is not meant for applications that need transactional data consistency 🚫.

bestie, this protocol sends all the visible values of entries in the content whenever something changes, instead of just the change deltas πŸ“¦. So it's not a good fit for bandwidth-challenged applications or deployments πŸ“ΆπŸ’€.

1.3. Overview πŸ¦‹

this section gives an overview of the basic ways the Sync Operation can keep a synchronized client copy of a DIT fragment in sync 🧚.

  • Polling for changes: refreshOnly mode
  • Listening for changes: refreshAndPersist mode

That's the first chunk, babe 🌈✨ More parts are coming, so stay tuned πŸ’…

1.3.1. Polling for Changes (refreshOnly) πŸ”

okay so first things first, the client needs its very first copy πŸŽ€. It sends a Sync request, which is just a search request with the Sync Request Control set to mode refreshOnly. The server answers pretty much like a normal search: it hands back the content matching the search criteria (baseObject, scope, filter, attributes), subject to access controls and other restrictions πŸ”’. The difference is that with each entry it also sends a Sync State Control with state add. That control carries the entry's Universally Unique Identifier (UUID) [UUID] of the entry [RFC4530]. Here's the best part: a DN can change over time, but an entry's UUID is stable πŸ’–. The initial content gets wrapped up with a SearchResultDone that has a Sync Done Control, and that Sync Done Control gives you a syncCookie. The syncCookie represents session state ✨.

To poll for updates, the client reissues the Sync Operation with the syncCookie it got last time πŸ”„. The server works out what content would be returned as if this were a normal search. But now it uses the syncCookie to remember what the client was already sent, so it only sends copies of entries that have changed, each with a Sync State Control with state add. For every changed entry, all attributes belonging to the content get sent, whether they were modified or not πŸ’….

The server may use either or both of the two synchronization phases that are told apart by how they handle entries that were deleted from the content: the present phase and the delete phase 🧚. If the server uses just one phase for the refresh stage, each phase is closed off by a SearchResultDone with a Sync Done Control. A present phase is marked by a FALSE refreshDeletes value in the Sync Done Control, and a delete phase is marked by a TRUE refreshDeletes value. The present phase can be followed by a delete phase. The two phases are separated by a refreshPresent Sync Info Message with a FALSE refreshDone value. When both phases are used, the present phase brings the client copy up to the state where the delete phase can start 🌸.

In the present phase, the server sends an empty entry (no attributes) with a Sync State Control with state present for each unchanged entry πŸ¦‹.

The delete phase may be used when the server can reliably tell which entries in the old client copy are no longer in the content, and the number of those entries is less than or equal to the number of unchanged entries πŸ™ˆ. In delete mode, the server sends an empty entry with a Sync State Control with state delete for each entry that's gone from the content, instead of sending an empty entry with state present for every entry that's still there.

The server may also send syncIdSet Sync Info Messages that hold a set of UUIDs, either for unchanged present entries or for deleted entries, instead of sending a bunch of separate messages πŸ“. If refreshDeletes in the syncIdSet is FALSE, the UUIDs of unchanged present entries are in the syncUUIDs set. If refreshDeletes in the syncIdSet is TRUE, the UUIDs of entries that are no longer in the content are in the syncUUIDs set. An optional cookie can be included in the syncIdSet to represent the state of the content after the presence or absence of the entries in the syncUUIDs set has been synchronized 🫢.

The client is the one that builds the synchronized copy of the DIT fragment πŸ‘‘.

If refreshDeletes in the syncDoneValue is FALSE, the new copy includes all changed entries returned by the reissued Sync Operation, plus all unchanged entries that the reissued Sync Operation identified as present (their content comes from the previous Sync Operation). Any unchanged entries that weren't identified as present get deleted from the client content, because they were either deleted, moved, or otherwise scoped out of the content πŸ—‘οΈ.

If refreshDeletes in the syncDoneValue is TRUE, the new copy includes all changed entries returned by the reissued Sync Operation, plus every other entry from the previous copy except the ones identified as having been deleted from the content 🌈.

The client can come back later and re-poll for changes to this synchronized client copy whenever it wants πŸ”βœ¨.

1.3.2. Listening for Changes (refreshAndPersist) πŸ‘‚

polling for changes can be super expensive for the server, the client, and the network, ngl 😩. That's where refreshAndPersist comes in. It lets the server actively send updates for entries that change in the content, so nobody has to keep asking πŸ’….

When the client picks refreshAndPersist mode, it's asking the server to send updates for entries that change after the initial refresh content is worked out πŸŽ€. Instead of sending a SearchResultDone like it does for polling, the server sends a Sync Info Message to say the refresh stage is done, and then it moves into the persist stage. After the client gets that Sync Info Message, it builds its synchronized copy the same way as described in Section 1.3.1 πŸ“–.

After that, the server may send change notifications that come from the original Sync search request, which now stays open on the server πŸ¦‹. For entries being added to the returned content, the server sends a SearchResultEntry (with attributes) with a Sync State Control with state add. For entries being deleted from the content, the server sends a SearchResultEntry with no attributes and a Sync State Control with state delete. For entries being modified in the returned content, the server sends a SearchResultEntry (with attributes) with a Sync State Control with state modify ✨.

When an entry is modified, all attributes belonging to the content get sent, whether they were modified or not πŸ’–.

Heads up, though: renaming an entry in the DIT can cause three different things at once 😭. It can cause an add state change where the entry gets renamed into the content, a delete state change where it gets renamed out of the content, and a modify state change where it stays in the content. Also, changing an entry in the DIT can cause an add, delete, or modify state change to the content 🌸.

Once the client gets a change notification, it updates its copy of the content 🫢.

If the server wants to update the syncCookie during the persist stage, it can include the syncCookie in any Sync State Control or Sync Info Message it sends back πŸ“.

The operation keeps going until the client cancels it [RFC3909] or the server terminates it. A Sync Done Control shall be attached to the SearchResultDone Message to provide a new syncCookie πŸ‘‘.

1.4. Conventions πŸ“

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] 🧠.

Protocol elements are described using ASN.1 [X.680] with implicit tags 🧩. The term "BER-encoded" means the element is to be encoded using the Basic Encoding Rules [X.690] under the restrictions detailed in Section 5.1 of [RFC4511] πŸ”.

2. Elements of the Sync Operation ⭐

The Sync Operation is defined as an extension to the LDAP Search Operation [RFC4511]. The directory user agent (DUA or client) submits a SearchRequest Message with a Sync Request Control, and the directory system agent (DSA or server) responds with zero or more SearchResultEntry Messages, each with a Sync State Control. It can also send zero or more SearchResultReference Messages, each with a Sync State Control, zero or more Sync Info Intermediate Response Messages, and a SearchResultDone Message with a Sync Done Control πŸŽ€.

To help clients discover support for this operation, servers implementing it SHOULD publish 1.3.6.1.4.1.4203.1.9.1.1 as a value of the supportedControl attribute [RFC4512] of the root DSA-specific entry (DSE) πŸ”. A server MAY choose to advertise this extension only when the client is authorized to use it πŸ”’.

2.1. Common ASN.1 Elements 🧩

2.1.1. syncUUID

The syncUUID data type is an OCTET STRING holding a 128-bit (16-octet) Universally Unique Identifier (UUID) [UUID] πŸ†”.

   syncUUID ::= OCTET STRING (SIZE(16))
        -- constrained to UUID

2.1.2. syncCookie πŸͺ

The syncCookie is a notational convenience. Even though the syncCookie type is encoded as an OCTET STRING, its value is an opaque value that holds information about the synchronization session and its state 🫧. Usually the session information includes a hash of the operation parameters that the server requires not be changed, and the synchronization state information includes a commit (log) sequence number, a change sequence number, or a time stamp ⏰. For convenience of description, the term "no cookie" refers either to a null cookie or to a cookie with pre-initialized synchronization state πŸ’œ.

   syncCookie ::= OCTET STRING

2.2. Sync Request Control πŸŽ›οΈ

The Sync Request Control is an LDAP Control [RFC4511] where the controlType is the object identifier 1.3.6.1.4.1.4203.1.9.1.1. Its controlValue, an OCTET STRING, contains a BER-encoded syncRequestValue. The criticality field is either TRUE or FALSE πŸ’….

   syncRequestValue ::= SEQUENCE {
       mode ENUMERATED {
           -- 0 unused
           refreshOnly       (1),
           -- 2 reserved
           refreshAndPersist (3)
       },
       cookie     syncCookie OPTIONAL,
       reloadHint BOOLEAN DEFAULT FALSE
   }

The Sync Request Control is only applicable to the SearchRequest Message 🎯.

2.3. Sync State Control 🏷️

The Sync State Control is an LDAP Control [RFC4511] where the controlType is the object identifier 1.3.6.1.4.1.4203.1.9.1.2. Its controlValue, an OCTET STRING, contains a BER-encoded syncStateValue. The criticality is FALSE 🌷.

   syncStateValue ::= SEQUENCE {
       state ENUMERATED {
           present (0),
           add (1),
           modify (2),
           delete (3)
       },
       entryUUID syncUUID,
       cookie    syncCookie OPTIONAL
   }

The Sync State Control is only applicable to SearchResultEntry and SearchResultReference Messages πŸ¦‹.

2.4. Sync Done Control 🏁

The Sync Done Control is an LDAP Control [RFC4511] where the controlType is the object identifier 1.3.6.1.4.1.4203.1.9.1.3. Its controlValue contains a BER-encoded syncDoneValue. The criticality is FALSE (and hence absent) πŸ™ƒ.

   syncDoneValue ::= SEQUENCE {
       cookie          syncCookie OPTIONAL,
       refreshDeletes  BOOLEAN DEFAULT FALSE
   }

The Sync Done Control is only applicable to the SearchResultDone Message πŸ’«.

2.5. Sync Info Message πŸ“¨

The Sync Info Message is an LDAP Intermediate Response Message [RFC4511] where the responseName is the object identifier 1.3.6.1.4.1.4203.1.9.1.4. Its responseValue contains a BER-encoded syncInfoValue. The criticality is FALSE (and hence absent) πŸ₯°.

   syncInfoValue ::= CHOICE {
       newcookie      [0] syncCookie,
       refreshDelete  [1] SEQUENCE {
           cookie         syncCookie OPTIONAL,
           refreshDone    BOOLEAN DEFAULT TRUE
       },
       refreshPresent [2] SEQUENCE {
           cookie         syncCookie OPTIONAL,
           refreshDone    BOOLEAN DEFAULT TRUE
       },
       syncIdSet      [3] SEQUENCE {
           cookie         syncCookie OPTIONAL,
           refreshDeletes BOOLEAN DEFAULT FALSE,
           syncUUIDs      SET OF syncUUID
       }
   }

2.6. Sync Result Codes πŸ’…

okay so there's exactly one LDAP resultCode [RFC4511] defined for this, and it's a big one πŸ‘‘

e-syncRefreshRequired (4096)

3. Content Synchronization πŸ”₯

okay bestie, the Sync Operation kicks off when the client sends a SearchRequest Message with a Sync Request Control πŸ¦‹

no cookie (or a cookie with no initialized synchronization state in it) means "gimme the initial content" πŸ“ while a cookie that represents the state of a client copy means "just send me the updates pls" ✨ Synchronization Sessions are covered in Section 3.1, and Content Determination is in Section 3.2.

the mode is either refreshOnly or refreshAndPersist. those get their own sections (3.3 and 3.4). refreshOnly is just a refresh stage, while refreshAndPersist is a refresh stage followed by a persist stage 🌈

3.1. Synchronization Session πŸŽ€

a bunch of Sync Operations in a row, where the last cookie the server gave back for one gets handed to the server in the next one, is called a Synchronization Session. same friend group, same session 🫢

the client MUST specify the same content-controlling parameters (see Section 3.5) in each Search Request of the session. the client SHOULD also issue each Sync request of a session under the same authentication and authorization associations with equivalent integrity and protections. if the server does not recognize the request cookie, or the request is made under different associations or non-equivalent protections, the server SHALL return the initial content as if no cookie had been provided, or return an empty content with the e-syncRefreshRequired LDAP result code. the decision between returning the initial content and returning the empty content with the e-syncRefreshRequired result code MAY be based on reloadHint in the Sync Request Control from the client. if the server recognizes the request cookie as representing empty or initial synchronization state of the client copy, the server SHALL return the initial content πŸ’–

a Synchronization Session may span multiple LDAP sessions between the client and the server. the client SHOULD issue each Sync request of a session to the same server. (Note: Shadowing considerations are discussed in Section 6.) πŸ‘€

3.2. Content Determination 🧚

the content to be provided is determined by the parameters of the Search Request, as described in [RFC4511], and possibly other controls. the same content parameters SHOULD be used in each Sync request of a session. if different content is requested and the server is unwilling or unable to process the request, the server SHALL return the initial content as if no cookie had been provided, or return an empty content with the e-syncRefreshRequired LDAP result code. the decision between returning the initial content and returning the empty content with the e-syncRefreshRequired result code MAY be based on reloadHint in the Sync Request Control from the client ✨

the content may not necessarily include all entries or references that would be returned by a normal search operation, nor, for those entries included, all attributes returned by a normal search. so when the server is unwilling or unable to provide synchronization for any attribute for a set of entries, the server MUST treat all filter components matching against these attributes as Undefined and MUST NOT return these attributes in SearchResultEntry responses. πŸ™ˆ

servers SHOULD support synchronization for all non-collective user-application attributes for all entries πŸ’…

the server may also return continuation references to other servers or to itself. the latter is allowed, since the server may partition the entries it holds into separate synchronization contexts 🌸

the client may chase all or some of these continuations, each as a separate content synchronization session πŸ¦‹

3.3. refreshOnly Mode 🌷

a Sync request with mode refreshOnly and with no cookie is a poll for initial content. a Sync request with mode refreshOnly and with a cookie representing a synchronization state is a poll for content update πŸ”₯

3.3.1. Initial Content Poll πŸ“

when the request comes in, the server gives back the initial content using a set of zero or more SearchResultEntry and SearchResultReference Messages, followed by a SearchResultDone Message 🎁

each SearchResultEntry Message SHALL include a Sync State Control of state add, an entryUUID containing the entry's UUID, and no cookie. each SearchResultReference Message SHALL include a Sync State Control of state add, an entryUUID containing the UUID associated with the reference (normally the UUID of the associated named referral [RFC3296] object), and no cookie. the SearchResultDone Message SHALL include a Sync Done Control having refreshDeletes set to FALSE πŸ’œ

a resultCode value of success means the operation successfully completed. otherwise, the result code tells you the nature of the failure. the server may return the e-syncRefreshRequired result code on the initial content poll if it is safe to do so, when it is unable to perform the operation for various reasons. reloadHint is set to FALSE in the SearchRequest Message requesting the initial content poll πŸ™ƒ

if the operation is successful, a cookie representing the synchronization state of the current client copy SHOULD be returned for use in subsequent Sync Operations ✨

3.3.2. Content Update Poll 🫧

when the request comes in, the server provides the content refresh using a set of zero or more SearchResultEntry and SearchResultReference Messages, followed by a SearchResultDone Message πŸ’«

the server is REQUIRED to:

  • a) provide the sequence of messages necessary for eventual convergence of the client's copy of the content to the server's copy,
  • b) treat the request as an initial content request (e.g., ignore the cookie or the synchronization state represented in the cookie),
  • c) indicate that the incremental convergence is not possible by returning e-syncRefreshRequired,
  • d) return a resultCode other than success or e-syncRefreshRequired.

a Sync Operation may consist of a single present phase, a single delete phase, or a present phase followed by a delete phase 🌈

in each phase, for each entry or reference that has been added to the content or changed since the previous Sync Operation indicated by the cookie, the server returns a SearchResultEntry or SearchResultReference Message, respectively. each one has a Sync State Control consisting of state add, an entryUUID containing the UUID of the entry or reference, and no cookie. each SearchResultEntry Message represents the current state of a changed entry. each SearchResultReference Message represents the current state of a changed reference πŸ“

in the present phase, for each entry that has not changed since the previous Sync Operation, an empty SearchResultEntry is returned whose objectName reflects the entry's current DN, whose attributes field is empty, and whose Sync State Control consists of state present, an entryUUID containing the UUID of the entry, and no cookie. for each reference that has not changed since the previous Sync Operation, an empty SearchResultReference containing an empty SEQUENCE OF LDAPURL is returned, with a Sync State Control consisting of state present, an entryUUID containing the UUID of the entry, and no cookie. no messages are sent for entries or references that are no longer in the content πŸ¦‹

multiple empty entries with a Sync State Control of state present SHOULD be coalesced into one or more Sync Info Messages of syncIdSet value, with refreshDeletes set to FALSE. syncUUIDs contain a set of UUIDs of the entries and references that haven't changed since the last Sync Operation. syncUUIDs may be empty. the Sync Info Message of syncIdSet may contain a cookie to represent the state of the content after performing the synchronization of the entries in the set 🌸

in the delete phase, for each entry no longer in the content, the server returns a SearchResultEntry whose objectName reflects a past DN of the entry or is empty, whose attributes field is empty, and whose Sync State Control consists of state delete, an entryUUID containing the UUID of the deleted entry, and no cookie. for each reference no longer in the content, a SearchResultReference containing an empty SEQUENCE OF LDAPURL is returned, with a Sync State Control consisting of state delete, an entryUUID containing the UUID of the deleted reference, and no cookie πŸ’€

multiple empty entries with a Sync State Control of state delete SHOULD be coalesced into one or more Sync Info Messages of syncIdSet value, with refreshDeletes set to TRUE. syncUUIDs contain a set of UUIDs of the entries and references that have been deleted from the content since the last Sync Operation. syncUUIDs may be empty. the Sync Info Message of syncIdSet may contain a cookie to represent the state of the content after performing the synchronization of the entries in the set 🧚

when a present phase is followed by a delete phase, the two phases are delimited by a Sync Info Message containing syncInfoValue of refreshPresent, which may contain a cookie representing the state after completing the present phase. the refreshPresent contains refreshDone, which is always FALSE in the refreshOnly mode of a Sync Operation, because it is followed by a delete phase πŸ’…

if a Sync Operation consists of a single phase, each phase (and therefore the Sync Operation) is marked as ended by a SearchResultDone Message with a Sync Done Control, which SHOULD contain a cookie representing the state of the content after completing the Sync Operation. the Sync Done Control contains refreshDeletes, which is set to FALSE for the present phase and set to TRUE for the delete phase πŸŽ€

if a Sync Operation consists of a present phase followed by a delete phase, the Sync Operation is marked as ended at the end of the delete phase by a SearchResultDone Message with a Sync Done Control, which SHOULD contain a cookie representing the state of the content after completing the Sync Operation. the Sync Done Control contains refreshDeletes, which is set to TRUE ✨

the client can say whether it prefers to receive an initial content by supplying reloadHint of TRUE, or to receive an e-syncRefreshRequired resultCode by supplying reloadHint of FALSE (hence absent). this applies in the case that the server determines it is impossible or inefficient to achieve eventual convergence by continuing the current incremental synchronization thread πŸ”₯

a resultCode value of success means the operation is successfully completed. a resultCode value of e-syncRefreshRequired means a full or partial refresh is needed. otherwise, the result code tells you the nature of the failure. a cookie is provided in the Sync Done Control for use in subsequent Sync Operations for incremental synchronization πŸ’–

3.4. refreshAndPersist Mode 🌈

a Sync request with mode refreshAndPersist asks for initial content or a content update (during the refresh stage), followed by change notifications (during the persist stage) πŸ¦‹πŸ«Ά

3.4.1. refresh Stage ✨

okay so the content refresh works exactly like I explained in Section 3.3 πŸ’–, with one twist at the finish line. Instead of a SearchResultDone Message with resultCode success, the server sends a Sync Info Message of refreshDelete or refreshPresent with refreshDone set to TRUE to say "refresh is done, bestie" πŸŽ€. A cookie SHOULD be returned in the Sync Info Message to represent the state of the content after finishing the refresh stage of the Sync Operation πŸ“.

3.4.2. persist Stage πŸ¦‹

this is where the change notifications happen πŸ””.

As updates are made to the DIT, the server lets the client know about changes to the content. DIT updates may cause entries and references to be added to the content, deleted from the content, or modified within the content. DIT updates may also cause references to be added, deleted, or modified within the content.

when DIT updates cause an entry to be added to the content, the server sends a SearchResultEntry Message that shows the entry the way it appears in the content 🧚. The message SHALL include a Sync State Control with state of add, an entryUUID containing the entry's UUID, and an optional cookie.

when DIT updates cause a reference to be added to the content, the server sends a SearchResultReference Message that shows the reference the way it appears in the content. The message SHALL include a Sync State Control with state of add, an entryUUID containing the UUID associated with the reference, and an optional cookie.

when DIT updates cause an entry to be modified within the content, the server sends a SearchResultEntry Message that shows the entry as it appears in the content. The message SHALL include a Sync State Control with state of modify, an entryUUID containing the entry's UUID, and an optional cookie ✨.

when DIT updates cause a reference to be modified within the content, the server sends a SearchResultReference Message that shows the reference as it appears in the content. The message SHALL include a Sync State Control with state of modify, an entryUUID containing the UUID associated with the reference, and an optional cookie.

when DIT updates cause an entry to be deleted from the content, the server sends a SearchResultEntry Message with no attributes. The message SHALL include a Sync State Control with state of delete, an entryUUID containing the entry's UUID, and an optional cookie πŸ—‘οΈ.

when DIT updates cause a reference to be deleted from the content, the server sends a SearchResultReference Message with an empty SEQUENCE OF LDAPURL. The message SHALL include a Sync State Control with state of delete, an entryUUID containing the UUID associated with the reference, and an optional cookie.

Multiple empty entries with a Sync State Control of state delete SHOULD be coalesced into one or more Sync Info Messages of syncIdSet value with refreshDeletes set to TRUE. syncUUIDs contain a set of UUIDs of the entries and references that have been deleted from the content. The Sync Info Message of syncIdSet may contain a cookie to represent the state of the content after performing the synchronization of the entries in the set 🫢.

with each of these messages, the server may provide a new cookie to be used in later Sync Operations. The server may also return Sync Info Messages of choice newCookie to hand over a new cookie. The client SHOULD use the newest (last) cookie it got from the server in later Sync Operations. main character energy, cookie edition πŸͺπŸ‘‘.

3.5. Search Request Parameters πŸŽ€

as I said in Section 3.1, the client SHOULD specify the same content-controlling parameters in each Search Request of the session. Every field of the SearchRequest Message counts as a content-controlling parameter except for sizeLimit and timeLimit πŸ’….

3.5.1. baseObject 🌸

just like a normal search, the refresh and persist stages are not isolated from DIT changes. The entry the baseObject points to could get deleted, renamed, or moved. It's also possible that the alias object used to find that entry gets changed, so the baseObject ends up pointing at a different entry 😭.

If the DIT gets updated during a Sync Operation in a way that means the baseObject no longer refers to any entry, or changes which entry it refers to, the server SHALL return an appropriate non-success result code, such as noSuchObject, aliasProblem, aliasDereferencingProblem, referral, or e-syncRefreshRequired 🚨.

3.5.2. derefAliases 🧁

this operation doesn't do alias dereferencing during searching, so no drama there πŸ™…β€β™€οΈ. The client SHALL specify neverDerefAliases or derefFindingBaseObj for the SearchRequest derefAliases parameter. The server SHALL treat other values (e.g., derefInSearching, derefAlways) as protocol errors ❌.

3.5.3. sizeLimit 🍭

the sizeLimit only applies to entries (no matter what their state is in the Sync State Control) that get returned during the refreshOnly operation or the refresh stage of the refreshAndPersist operation ✨.

3.5.4. timeLimit ⏰

for a refreshOnly Sync Operation, the timeLimit covers the whole operation. For a refreshAndPersist operation, the timeLimit only covers the refresh stage, including the generation of the Sync Info Message with a refreshDone value of TRUE 🫧.

3.5.5. filter πŸ”

the client SHOULD avoid filter assertions that apply to the values of attributes the server is likely to treat as holding meta-information. See Section 4 πŸ™ˆ.

3.6. objectName 🏷️

the Sync Operation uses the entryUUID values from the Sync State Control as the primary keys to entries πŸ”‘. The client MUST use these entryUUIDs to correlate synchronization messages. no skipping this one, bestie πŸ’€.

sometimes the DN that comes back won't match the entry's current DN. Like, when an entry is being deleted from the content, the server may send an empty DN if it doesn't want to reveal the entry's current DN (or, if the entry was deleted from the DIT, its last DN) 🌈.

also, the entry's DN may be seen as meta information (see Section 4.1) πŸ§šβ€β™€οΈ.

3.7. Canceling the Sync Operation πŸ›‘

Servers MUST implement the LDAP Cancel [RFC3909] Operation and support cancellation of outstanding Sync Operations as described here πŸ”₯.

to cancel an outstanding Sync Operation, the client issues an LDAP Cancel [RFC3909] Operation πŸ’œ.

if at any point the server becomes unwilling or unable to keep processing a Sync Operation, the server SHALL return a SearchResultDone with a non-success resultCode that tells the client why the operation ended πŸ™ƒ.

whether the client or the server started the termination, the server may give a cookie in the Sync Done Control for use in later Sync Operations 🎁.

3.8. Refresh Required πŸ”„

so, to reach eventually-convergent synchronization, the server may end the Sync Operation during the refresh or persist stages by returning an e-syncRefreshRequired resultCode to the client. If no cookie is provided, a full refresh is needed. If a cookie representing a synchronization state is provided in this response, an incremental refresh is needed 🫠.

to get a full refresh, the client issues a new synchronization request with no cookie. To get an incremental reload, the client issues a new synchronization with the provided cookie 🌷.

the server may choose to send a full copy in the refresh stage (for example, by ignoring the cookie or the synchronization state represented in the cookie) instead of an incremental refresh, so it can reach eventual convergence πŸ’«.

whether the server sends the initial content or the e-syncRefreshRequired result code may depend on the reloadHint in the Sync Request Control from the client 🎯.

in the case of persist stage Sync, the server returns the resultCode of e-syncRefreshRequired to tell the client it needs to issue a new Sync Operation to get a synchronized copy of the content. If no cookie is provided, a full refresh is needed. If a cookie representing a synchronization state is provided, an incremental refresh is needed πŸ’….

the server may also return e-syncRefreshRequired if it decides that a refresh would be more efficient than sending all the messages needed for convergence ⚑.

heads up: the client may receive one or more of SearchResultEntry, SearchResultReference, and/or Sync Info Messages before it gets a SearchResultDone Message with the e-syncRefreshRequired result code πŸ‘€.

3.9. Chattiness Considerations πŸ—£οΈ

okay so chattiness is basically about not yapping more than you need to 😭 The server MUST make sure the number of entry messages it sends to refresh the client never goes over the number of entries currently in the content πŸ’…. Servers don't have to keep history, which is fine, but if a server has enough history to reliably figure out which entries in the client's old copy are gone, and there aren't more of those gone entries than unchanged ones, it SHOULD send delete entry messages instead of present entry messages (see Section 3.3.2) ✨.

When the history a server keeps isn't enough for clients doing infrequent refreshOnly Sync Operations, the server probably has incomplete history by the time those clients reconnect (like if it got truncated) πŸ™ˆ.

The server SHOULD NOT resort to a full reload when its history isn't enough to generate delete entry messages 🚫. It SHOULD generate either present entry messages only, or present entry messages followed by delete entry messages to bring the client copy to the current state. In the second case, the present entry messages bring the client copy to a state covered by the history the server keeps 🧚.

The server SHOULD maintain enough state information (such as a context-wide last modify time stamp) to tell if nothing changed in the context since the content refresh was provided. When nothing changed, it can generate zero delete entry messages instead of present messages 🌸.

The server SHOULD NOT use the history information when that doesn't reduce the synchronization traffic, or when using it could expose sensitive information the client isn't allowed to receive πŸ”.

Server implementors should also think about chattiness across multiple Sync Operations in one session πŸŽ€. As noted in Section 3.8, the server may return e-syncRefreshRequired if it decides a reload would be more efficient than continuing under the current operation. If reloadHint in the Sync Request is TRUE, the server may start a reload without directing the client to request one πŸ”„.

The server SHOULD transfer a new cookie frequently so it doesn't have to transfer information the client already has πŸͺ. Even when DIT changes don't cause content synchronization changes, it may be worth providing a new cookie using a Sync Info Message. Still, the server SHOULD avoid overloading the client or network with Sync Info Messages πŸ™…β€β™€οΈ.

During persist mode, the server SHOULD coalesce multiple outstanding messages that update the same entry 🫧. The server MAY delay generating an entry update in anticipation of later changes to that entry that could be coalesced. The delay should be long enough to let back-to-back update requests get coalesced, but short enough that the temporary inconsistency caused by the delay gets fixed in a timely way ⏱️.

The server SHOULD use the syncIdSet Sync Info Message when there are multiple delete or present messages, to cut down on synchronization traffic πŸ“‰.

Also, lots of clients can be interested in the same directory change, and a server trying to service all of them at once can congest the network 🚦. The congestion gets even worse when the change needs a big transfer to each interested client. Implementors and deployers of servers should take steps to prevent and manage network congestion πŸ’œ.


3.10. Operation Multiplexing πŸŒ€

The LDAP protocol model [RFC4511] lets operations be multiplexed over a single LDAP session 🧡. Clients SHOULD NOT maintain multiple LDAP sessions with the same server. Servers SHOULD ensure that responses from concurrently processed operations are interleaved fairly βš–οΈ.

Clients SHOULD combine Sync Operations whose result sets are largely overlapping 🀝. This avoids having to return multiple messages, one for each overlapping session, when entries in the overlap change.

Clients SHOULD NOT combine Sync Operations whose result sets are largely non-overlapping πŸ™…β€β™€οΈ. This makes sure an event that needs an e-syncRefreshRequired response can be limited to as few result sets as possible.


4. Meta Information Considerations πŸŽ€

4.1. Entry DN πŸ“›

An entry's DN is built from its relative DN (RDN) and its parent's DN, so people often treat it as meta information 🧐.

Renaming an entry or moving it under a new superior changes its DN, but that change SHOULD NOT, by itself, cause synchronization messages to be sent for that entry πŸ™Œ. Still, if the rename or move could make the entry get added to or deleted from the content, appropriate synchronization messages should be generated so the client knows πŸ“¬.

When a server treats the entry's DN as meta information, the server SHALL either:

  • evaluate all MatchingRuleAssertions [RFC4511] to TRUE if matching a value of an attribute of the entry, otherwise Undefined, or
  • evaluate all MatchingRuleAssertion with dnAttributes of TRUE as Undefined.

The second choice is offered to make the server easier to implement πŸ› οΈ.

4.2. Operational Attributes βš™οΈ

When the values of an operational attribute come from values not held as part of the entry it appears in, the operational attribute SHOULD NOT support synchronization of that attribute 🚫.

For example, servers that implement the X.501 subschema model [X.501] should not support synchronization of the subschemaSubentry attribute, since its value comes from values held and administered in subschema subentries πŸ“š.

As a counter example, servers that implement aliases [RFC4512][X.501] can support synchronization of the aliasedObjectName attribute, since its values are held and administered as part of the alias entries πŸͺž.

Servers SHOULD support synchronization of these operational attributes: createTimestamp, modifyTimestamp, creatorsName, modifiersName [RFC4512] πŸ•°οΈ. Servers MAY support synchronization of other operational attributes 🌈.

4.3. Collective Attributes πŸ‘­

A collective attribute is "a user attribute whose values are the same for each member of an entry collection" [X.501]. How collective attributes get used in LDAP is covered in [RFC3671] πŸ“–.

Changing a collective attribute usually affects the content of multiple entries, which are the members of the collection πŸ’₯. It's inefficient to include the values of collective attributes visible in the entries of the collection, because a single change to a collective attribute needs a separate SearchResultEntry for each entry the change affected πŸ˜΅β€πŸ’«.

Servers SHOULD NOT synchronize collective attributes that appear in entries of any collection πŸ™…β€β™€οΈ. Servers MAY support synchronization of collective attributes that appear in collective attribute subentries πŸ’….

4.4. Access and Other Administrative Controls πŸ”‘

Entries are often subject to access and other administrative Controls πŸ‘€. Some of the policy information for an entry may live in the entry itself, but it's often kept somewhere else too (in superior entries, in subentries, in the root DSE, in configuration files, and so on). Because of that, changes to policy information make it hard to get eventual convergence during incremental synchronization πŸŒ€.

When it's impractical or infeasible to generate content changes from a policy change, servers may choose to return e-syncRefreshRequired, or treat the Sync Operation as an initial content request (for example, by ignoring the cookie or the synchronization state the cookie represents) 🫠.


5. Interaction with Other Controls 🧩

The Sync Operation may be used with:

as described below. It may also be used with other LDAP extensions, which are detailed in other documents πŸ’–.

5.1. ManageDsaIT Control 🏠

The ManageDsaIT Control [RFC3296] says the operation acts on the DSA Information Tree, and it causes referral and other special entries to be treated as object entries for that operation πŸͺ„.

5.2. Subentries Control πŸ‘€

The Subentries Control is used with the search operation to "control the visibility of entries and subentries which are within scope" [RFC3672] πŸ”. When it's used with the Sync Operation, the subentries control and other factors (search scope, filter, and so on) decide whether an entry or subentry shows up in the content βœ….


6. Shadowing Considerations πŸ‘―

As noted in [RFC4511], some servers may hold shadow copies of entries that can be used to answer search and comparison queries πŸͺž. Those servers may also support content synchronization requests. This section talks through what implementors and deployers should think about when they put the Sync operation into shadowed directories 🧠.

A client might know about several servers that are equally capable of giving it particular directory content, but the client SHOULD NOT assume that each of them is equally capable of continuing a content synchronization session πŸ™…β€β™€οΈ. As stated in Section 3.1, the client SHOULD issue each Sync request of a Sync session to the same server 🎯.

Through domain naming, IP address redirection, or other techniques, multiple physical servers can be made to look like one logical server to a client 🎭. Only servers that are equally capable when it comes to supporting the Sync operation, and that hold equally complete copies of the entries, should be made to look like one logical server ✨. In particular, each physical server acting as one logical server SHOULD be equally capable of continuing a content synchronization based on cookies provided by any of the other physical servers, without needing a full reload πŸ”. There's no standard LDAP shadowing mechanism, so how to independently implement equally capable servers (and the precise definition of "equally capable") is left to future documents πŸ“.

It may be hard for a server to reliably figure out what content another server gave to the client, especially in shadowing environments that let shadowing events get coalesced 🌫️. For those servers, using the delete phase discussed in Section 3.3.2 may not be applicable πŸ’€.

7. Security Considerations πŸ”

Okay so, to keep a synced copy of the content, the client has to delete information from its copy the way we talked about above 🧹. BUT the client is allowed to remember stuff the server told it, kept separate from the copy it uses for syncing 🧠. How that knowledge gets managed is beyond the scope of this doc, so it's not our problem here πŸ€·β€β™€οΈ. Servers should be careful not to disclose information for content the client isn't authorized to have knowledge of and/or about 🚫. Protect your data, bestie! πŸ’…

The info you get from a series of refreshOnly Sync Operations is pretty similar to what you get from a series of Search Operations, but the persist stage may disclose additional info πŸ‘€. A client might be able to figure out things about the exact sequence of update operations that caused the content to change. Literally a detective moment πŸ•΅οΈβ€β™€οΈβœ¨.

Implementors should take precautions against malicious cookie content πŸͺ. That includes malformed cookies, and also valid cookies used with different security associations and/or protections, all in an attempt to sneak into information you're not supposed to see πŸ™ˆ. Servers may include a digital signature in the cookie to detect tampering, which is giving security guard energy πŸ›‘οΈ.

The operation may be the target of direct denial-of-service attacks ⚠️. Implementors should provide safeguards so the operation isn't abused. Servers may place access control or other restrictions upon the use of this operation 🚧.

πŸ’€ Here's the scary part: even small updates to the directory can generate a significant amount of traffic to clients using this operation. A user could abuse their update privileges to mount an indirect denial of service against these clients, other clients, and/or portions of the network. So servers should provide safeguards to make sure update operations aren't abused. No thank you πŸ™…β€β™€οΈ.

Implementors of this (or any) LDAP extension should be familiar with general LDAP security considerations [RFC4510] πŸ“š. Homework, but make it cute πŸŽ€.


8. IANA Considerations 🌸

Registration of the following values has been completed by the IANA [RFC4520]. Bookkeeping, but it matters! πŸ“‹

8.1. Object Identifier

The OID arc 1.3.6.1.4.1.4203.1.9.1 was assigned [ASSIGN] by the OpenLDAP Foundation. It sits under its IANA-assigned private enterprise allocation [PRIVATE], and it's for use in this specification πŸ¦‹.

8.2. LDAP Protocol Mechanism

The IANA has registered the LDAP Protocol Mechanism described in this document πŸŽ‰. Here's the registration, verbatim:

      Subject: Request for LDAP Protocol Mechanism Registration
      Object Identifier: 1.3.6.1.4.1.4203.1.9.1.1
      Description: LDAP Content Synchronization Control
      Person & email address to contact for further information:
          Kurt Zeilenga <kurt@openldap.org>
      Usage: Control
      Specification: RFC 4533
      Author/Change Controller: Kurt D. Zeilenga, Jong Hyuk Choi
      Comments: none

8.3. LDAP Result Codes

The IANA has registered the LDAP Result Code described in this document πŸ“. Here's that one too:

      Subject: LDAP Result Code Registration
      Person & email address to contact for further information:
          Kurt Zeilenga <kurt@OpenLDAP.org>
      Result Code Name: e-syncRefreshRequired (4096)
      Specification: RFC 4533
      Author/Change Controller: Kurt D. Zeilenga, Jong Hyuk Choi
      Comments:  none

9. Acknowledgements πŸ’œ

This doc borrows significantly from the LDAP Client Update Protocol [RFC3928], a product of the IETF LDUP working group 🫢. It also benefited from the Persistent Search [PSEARCH], Triggered Search [TSEARCH], and Directory Synchronization [DIRSYNC] works. And it borrows from "Lightweight Directory Access Protocol (v3)" [RFC2251] too. Shoutout to everybody who came before πŸ™Œ.


10. Normative References πŸ“–

   [RFC2119]   Bradner, S., "Key words for use in RFCs to Indicate
               Requirement Levels", BCP 14, RFC 2119, March 1997.

   [RFC3296]   Zeilenga, K., "Named Subordinate References in
               Lightweight Directory Access Protocol (LDAP)
               Directories", RFC 3296, July 2002.

   [RFC3671]   Zeilenga, K., "Collective Attributes in the Lightweight
               Directory Access Protocol (LDAP)", RFC 3671, December
               2003.

   [RFC3672]   Zeilenga, K., "Subentries in the Lightweight Directory
               Access Protocol (LDAP)", RFC 3672, December 2003.

   [RFC3909]   Zeilenga, K., "Lightweight Directory Access Protocol
               (LDAP) Cancel Operation", RFC 3909, October 2004.

   [RFC4510]   Zeilenga, K., Ed., "Lightweight Directory Access Protocol
               (LDAP): Technical Specification Road Map", RFC 4510, June
               2006.

   [RFC4511]   Sermersheim, J., Ed., "Lightweight Directory Access
               Protocol (LDAP): The Protocol", RFC 4511, June 2006.

   [RFC4512]   Zeilenga, K., "Lightweight Directory Access Protocol
               (LDAP): Directory Information Models", RFC 4512, June
               2006.

   [RFC4530]   Zeilenga, K., "Lightweight Directory Access Protocol
               (LDAP) entryUUID Operational Attribute", RFC 4530, June
               2006.

   [UUID]      International Organization for Standardization (ISO),
               "Information technology - Open Systems Interconnection -
               Remote Procedure Call", ISO/IEC 11578:1996

   [X.501]     International Telecommunication Union - Telecommunication
               Standardization Sector, "The Directory -- Models,"
               X.501(1993) (also ISO/IEC 9594-2:1994).

   [X.680]     International Telecommunication Union - Telecommunication
               Standardization Sector, "Abstract Syntax Notation One
               (ASN.1) - Specification of Basic Notation", X.680(1997)
               (also ISO/IEC 8824-1:1998).

   [X.690]     International Telecommunication Union - Telecommunication
               Standardization Sector, "Specification of ASN.1 encoding
               rules: Basic Encoding Rules (BER), Canonical Encoding
               Rules (CER), and Distinguished Encoding Rules (DER)",
               X.690(1997) (also ISO/IEC 8825-1:1998).

11. Informative References 🧚

   [RFC2251]   Wahl, M., Howes, T., and S. Kille, "Lightweight Directory
               Access Protocol (v3)", RFC 2251, December 1997.

   [RFC3928]   Megginson, R., Ed., Smith, M., Natkovich, O., and J.
               Parham, "Lightweight Directory Access Protocol (LDAP)
               Client Update Protocol (LCUP)", RFC 3928, October 2004.

   [RFC4520]   Zeilenga, K., "Internet Assigned Numbers Authority (IANA)
               Considerations for the Lightweight Directory Access
               Protocol (LDAP)", BCP 64, RFC 4520, June 2006.

   [PRIVATE]   IANA, "Private Enterprise Numbers",
               http://www.iana.org/assignments/enterprise-numbers.

   [ASSIGN]    OpenLDAP Foundation, "OpenLDAP OID Delegations",
               http://www.openldap.org/foundation/oid-delegate.txt.

   [X.500]     International Telecommunication Union - Telecommunication
               Standardization Sector, "The Directory -- Overview of
               concepts, models and services," X.500(1993) (also ISO/IEC
               9594-1:1994).

   [X.525]     International Telecommunication Union - Telecommunication
               Standardization Sector, "The Directory: Replication",
               X.525(1993).

   [DIRSYNC]   Armijo, M., "Microsoft LDAP Control for Directory
               Synchronization", Work in Progress.

   [PSEARCH]   Smith, M., et al., "Persistent Search: A Simple LDAP
               Change Notification Mechanism", Work in Progress.

   [TSEARCH]   Wahl, M., "LDAPv3 Triggered Search Control", Work in
               Progress.

Appendix A. CSN-based Implementation Considerations ✨

This appendix is just for info, bestie πŸ“š It is not a normative part of the LDAP Content Synchronization Operation's technical spec, so nobody's required to follow it.

It's all about LDAP Content Synchronization Operation server implementation stuff tied to Change Sequence Number (CSN) based approaches πŸ¦‹

CSN-based approaches are made for servers that don't keep history info (like change logs or state snapshots) about changes made to the Directory. So they have to rely on the current directory state plus a little bit of sync state tucked into the Sync Cookie πŸͺ Servers that do keep history info should consider other approaches that use that history. Lowkey smart 🧠

A Change Sequence Number is basically a timestamp with enough granularity to tell which of two updates to the same object happened first πŸ•°οΈ Don't mix CSNs up with Commit Sequence Numbers or Commit Log Record Numbers πŸ™…β€β™€οΈ A Commit Sequence Number tells you how two commits (to the same object or different objects) relate to each other in time. Meanwhile, a CSN tied to different entries might get committed out of order, which is so chaotic 😭 For the rest of this Appendix, "CSN" means Change Sequence Number.

In these approaches, the server keeps a CSN for each directory entry (the entry CSN), and also keeps a value we'll call the context CSN πŸ’œ The context CSN is the greatest committed entry CSN that is not greater than any outstanding (uncommitted) entry CSNs for all entries in a directory context. The context CSN values get used in syncCookie values as sync state indicators πŸŽ€

Here's the tea β˜• Search operations aren't isolated from individual directory update operations, and individual updates can't be assumed to be serialized. So you can't assume the returned content includes every relevant change whose CSN is less than or equal to the greatest entry CSN in the content πŸ™ˆ Here's how it actually breaks down:

  • The content includes all the relevant changes whose CSNs are less than or equal to the context CSN before search processing.
  • The content may also include any subset of the changes whose CSN is greater than the context CSN before search processing but less than or equal to the context CSN after search processing.
  • The content does not include any of the changes whose CSN is greater than the context CSN after search processing.

A simple server implementation could use the context CSN from before search processing to indicate state. That implementation would embed this value in each SyncCookie it returns, and we'll call it the cookie CSN 🌸 When a refresh is requested, the server would just generate update messages for all entries in the content whose CSN is greater than the supplied cookie CSN, and generate present messages for all the other entries in the content. ✨ But if the current context CSN is the same as the cookie CSN, the server should instead generate zero update messages and zero delete messages and indicate a refreshDeletes of TRUE, since the directory hasn't changed. Nothing happened, so nothing to send, periodt πŸ’…

The implementation should also think about changes to meta information, like access controls, that affect content determination πŸ‘€ One approach is for the server to keep a context-wide meta information CSN, or meta CSN. The meta CSN gets updated whenever meta information affecting content determination changes. If the meta CSN is greater than the cookie CSN, the server should ignore the cookie and treat the request as an initial request for content πŸ”₯

Heads up: a meta change can totally make an old cookie useless, so don't skip this check or your sync gets messy fr fr πŸ’€

Servers may also want to keep some per-session history info, which cuts down the number of messages that have to be sent during incremental refreshes πŸ¦‹ Specifically, a server could record info about entries as they leave the scope of a disconnected sync session, then use that info later to generate delete messages instead of present messages. Main character energy for efficiency πŸ‘‘

When the history info gets truncated, the CSN of the latest truncated history entry may be recorded as the truncated CSN of the history information 🧚 The truncated CSN can then be used to figure out whether a client's copy can be covered by the history info, by comparing it to the sync state in the cookie the client supplied. Very detective-core πŸ”

When there are lots and lots of sessions, it might make sense to keep this history only for selected clients 🫢 Servers taking this approach also need to consider resource consumption, so the server runs smoothly and is protected against abuse. It may be appropriate to restrict this mode of operation by policy. iykyk πŸ™ˆ


Authors' Addresses πŸŽ€

Kurt D. Zeilenga OpenLDAP Foundation

EMail: Kurt@OpenLDAP.org

Jong Hyuk Choi IBM Corporation

EMail: jongchoi@us.ibm.com

Copyright (C) The Internet Society (2006).

This document is subject to the rights, licenses and restrictions contained in BCP 78 and at www.rfc-editor.org/copyright.html, and except as set forth therein, the authors retain all their rights.

This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property 🌈

The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document, or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the procedures with respect to rights in RFC documents can be found in BCP 78 and BCP 79.

Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr.

The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.

Acknowledgement ⭐

Funding for the RFC Editor function is provided by the IETF Administrative Support Activity (IASA).

That's a wrap, bestie! RFC 4533 is fully served πŸŒˆπŸ’–βœ¨

πŸ“¦ where this page comes from