Sync State Control question

Gregory FARUCH gregory.faruch at sagemcom.com
Fri Mar 4 11:46:50 CET 2011


Hello,

When i delete a Member Uid attr form an entry with Luma, my python ldap
client receive a sync data, but how to get Sync State Control Value who
says that a deletion occurs (sync state value = 3).

I need to know what modification was made, add, delete, modify ?
Also why sever controls field is empty in the output and those controls
appear at the last elements of result data ?

I am using python-ldap version 2.4.0 and openldap version 2.4.23

Thanks for your answers.





==== THE CODE ====

import _ldap, ldap
import logging
import pprint
import re
import sys
import struct

import _ldap
from ldap.controls import LDAPControl
from ldap.cidict import cidict


class SyncStateControl(LDAPControl):
    """
    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 and the
    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.
    """
    controlType = '1.3.6.1.4.1.4203.1.9.1.2'

    def __init__(self, controlType='1.3.6.1.4.1.4203.1.9.1.2',
                 criticality=False, controlValue=None,
encodedControlValue=None):

        LDAPControl.__init__(self, self.controlType, criticality,
                             controlValue, encodedControlValue)

    def encodeControlValue(self, value):
        print 'STATE encode'

    def decodeControlValue(self, value):
        print 'STATE decode'



class SyncDoneControl(LDAPControl):
    """
    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 and the
    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.
    """
    controlType = '1.3.6.1.4.1.4203.1.9.1.3'

    def __init__(self, controlType='1.3.6.1.4.1.4203.1.9.1.3',
                 criticality=False, controlValue=None,
encodedControlValue=None):

        LDAPControl.__init__(self, self.controlType, criticality,
                             controlValue, encodedControlValue)

    def encodeControlValue(self, value):
        print 'DONE encode'

    def decodeControlValue(self, value):
        print 'DONE decode'


class SyncRequestControl(LDAPControl):
  # 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 and the
  # 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.

  controlType='1.3.6.1.4.1.4203.1.9.1.1'

  def __init__(self, controlType='1.3.6.1.4.1.4203.1.9.1.1',
               criticality=False,
               controlValue=None, encodedControlValue=None):
    ldap.controls.LDAPControl.__init__(self, self.controlType, criticality,
                                       controlValue, encodedControlValue)

  def encodeControlValue(self, value):
    # 30 31          Sequence tag (len=0x31)
    #       0a 01 01 Enumerated (len=0x01) value 0x01 (RefreshOnly)
    #       04 2C    Octet String (len=0x2C) value 'csn=...,rid=000'
    #                63 73 6e 3d 32 30 30 39 30 33 31 36 31 39 35 35
    #                30 39 5a 23 30 30 30 30 30 30 23 30 30 23 30 30
    #                30 30 30 30 2c 72 69 64 3d 30 30 30
    # return value
    mode, cookie, reload_hint = value

    # Enumerated (len=0x01) value 0x01 (RefreshOnly)
    result_content = struct.pack('BBB', 0x0A, 0x01, mode)

    # Octet String (optional)
    if cookie:
      result_content += struct.pack('BB', 0x04, len(cookie))
      result_content += cookie

    # Boolean (optional)
    if reload_hint:
      result_content += struct.pack('BBB', 0x01, 0x01, 0xFF)

    # Sequence tag
    result_header = struct.pack('BB', 0x30, len(result_content))

    return result_header + result_content

ldap.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3)
ldap.set_option(ldap.OPT_REFERRALS, 0)
ldap.controls.knownLDAPControls[SyncRequestControl.controlType] =
SyncRequestControl
ldap.controls.knownLDAPControls[SyncStateControl.controlType]   =
SyncStateControl
ldap.controls.knownLDAPControls[SyncDoneControl.controlType]    =
SyncDoneControl



conn = ldap.initialize('ldap://localhost', trace_level=0)
cookie = ''

cv = (3, cookie, False)
sync_req_ctrl=SyncRequestControl(criticality=False, controlValue=cv)
server_ctrls = (sync_req_ctrl,)


base =
"cn=the_cn_value,ou=the_ou_value,customAttr=custom_att_value,ou=bla,dc=example,dc=com"
op_id  = conn.search_ext(base,
                         ldap.SCOPE_SUBTREE,
                         '(objectClass=*)', [ '*', '+' ],
                         serverctrls = server_ctrls )

msg_id=op_id
all=0
timeout=60
add_ctrls=1
add_intermediates=1
add_extop=0
res_type, res_data, res_msgid, srv_ctrls, resp_name, resp_value =
conn.result4(msg_id,all,timeout,
add_ctrls,
add_intermediates,
add_extop)
print "res_type <%s>: "%res_type

while res_type:
    print "res_type <%s>: "%res_type
    print "res_data <%s>: "%pprint.pformat(res_data)
    print "res_msgid <%s>: "%res_msgid
    print "srv_ctrls <%s>: "%srv_ctrls
    print "resp_name <%s>: "%resp_name
    print "resp_value <%s>: "%resp_value
    print ''
    timeout=-1
    res_type, res_data, res_msgid, srv_ctrls, resp_name, resp_value =
conn.result4(msg_id,all,timeout,
add_ctrls,
add_intermediates,
add_extop)


==== THE OUTPUT ====


### Here The full synchronization because we send no cookie ####

res_type <100>:
res_type <100>:
res_data
<[('cn=the_cn_value,ou=the_ou_value,customAttr=custom_att_value,ou=bla,dc=example,dc=com',
  {
   'createTimestamp': ['20110301165220Z'],
   'entryCSN': ['20110303171738.236445Z#000000#002#000000'],
   'entryDN':
['cn=the_cn_value,ou=the_ou_value,customAttr=custom_att_value,ou=bla,dc=example,dc=com'],
   'entryUUID': ['c9446cba-d14e-47ab-bf95-5f08d5f85ea1'],
   'gidNumber': ['22035'],
   'hasSubordinates': ['FALSE'],
   'memberUid': ['memberUid 1', 'Member Uid 2', 'Member Uid 3'],
   'modifyTimestamp': ['20110303171738Z'],
   'subschemaSubentry': ['cn=Subschema']},
  [('1.3.6.1.4.1.4203.1.9.1.2',
    0,

'0\x15\n\x01\x01\x04\x10\xc9Dl\xba\xd1NG\xab\xbf\x95_\x08\xd5\xf8^\xa1')])]>:

res_msgid <1>:
srv_ctrls <[]>:
resp_name <None>:
resp_value <None>:


#### LAST Entry is an Intermediate result: Note that server controls are
empty !  ####

res_type <121>:
res_data <[(121,
  '1.3.6.1.4.1.4203.1.9.1.4',
  '\xa2>\x04<rid=000,sid=002,csn=20110303171738.236445Z#000000#002#000000',
  [])]>:
res_msgid <1>:
srv_ctrls <[]>:
resp_name <None>:
resp_value <None>:


#### AFTER A MemberUID deletion. Again Note that server ctrls are empty !
#####


res_type <100>:
res_data
<[('cn=the_cn_value,ou=the_ou_value,customAttr=custom_att_value,ou=bla,dc=example,dc=com',
  {
   'createTimestamp': ['20110301165220Z'],
   'entryCSN': ['20110303171931.545263Z#000000#002#000000'],
   'entryDN':
['cn=the_cn_value,ou=the_ou_value,customAttr=custom_att_value,ou=bla,dc=example,dc=com'],
   'entryUUID': ['c9446cba-d14e-47ab-bf95-5f08d5f85ea1'],
   'gidNumber': ['22035'],
   'hasSubordinates': ['FALSE'],
   'memberUid': ['memberUid 1', 'Member Uid 2'],  ### DELETION of Member
Uid 3
   'modifyTimestamp': ['20110303171931Z'],
   'subschemaSubentry': ['cn=Subschema']},
  [('1.3.6.1.4.1.4203.1.9.1.2',
    0,

'0S\n\x01\x02\x04\x10\xc9Dl\xba\xd1NG\xab\xbf\x95_\x08\xd5\xf8^\xa1\x04<rid=000,sid=002,csn=20110303171931.545263Z#000000#002#000000')])]>:

res_msgid <1>:
srv_ctrls <[]>:
resp_name <None>:
resp_value <None>:




#
" Ce courriel et les documents qui lui sont joints peuvent contenir des
informations confidentielles ou ayant un caractère privé. S'ils ne vous sont
pas destinés, nous vous signalons qu'il est strictement interdit de les
divulguer, de les reproduire ou d'en utiliser de quelque manière que ce
soit le contenu. Si ce message vous a été transmis par erreur, merci d'en
informer l'expéditeur et de supprimer immédiatement de votre système
informatique ce courriel ainsi que tous les documents qui y sont attachés."


                               ******

" This e-mail and any attached documents may contain confidential or
proprietary information. If you are not the intended recipient, you are
notified that any dissemination, copying of this e-mail and any attachments
thereto or use of their contents by any means whatsoever is strictly
prohibited. If you have received this e-mail in error, please advise the
sender immediately and delete this e-mail and all attached documents
from your computer system."
#




More information about the python-ldap mailing list