directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Apache Wiki <wikidi...@apache.org>
Subject [Directory Wiki] Update of "BindRequest" by EmmanuelLecharny
Date Sun, 04 Sep 2005 17:16:49 GMT
Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Directory Wiki" for change notification.

The following page has been changed by EmmanuelLecharny:
http://wiki.apache.org/directory/BindRequest

The comment on the change is:
Finished the BindRequest sample

------------------------------------------------------------------------------
  LDAPString ::= OCTET STRING
  }}}
  
+ == Java implementation ==
  We have a Java Bean which contains all the necessary informations. Here is the Class diagram
for this message :
  
- attachment:BindRequestDC.png
+ attachment:BindRequestCD.png
  
+ We have a kind of complicated structure to deal with ! In this class diagram, we have only
the data that are parts of the Ldap Message :
+ 
+ __Ldap Message structure :__
   * a MessageId : an integer between 0 and 2,147,483,647
-  * a protocolOp : it's another 
+  * a protocolOp : it contains the body of the BindRequest
+  * a list of controls
+ 
+ __BindRequest structure:__
   * a version : here it will always be the value '''3'''
   * a name : it can be null, if the user performs its authentication with '''SASL'''
+  * an authentication : it contains the authentication used
- - version: A version number indicating the version of the protocol to
-      be used in this protocol session.  This document describes version
-      3 of the LDAP protocol.  Note that there is no version negotiation,
-      and the client just sets this parameter to the version it desires.
-      If the client requests protocol version 2, a server that supports
-      the version 2 protocol as described in [2] will not return any v3-
  
+ __Simple authentication structure :__
+  * a simple : the password
-      specific protocol fields.  (Note that not all LDAP servers will
-      support protocol version 2, since they may be unable to generate
-      the attribute syntaxes associated with version 2.)
  
+ __SASL authentication structure :__
+  * a mechanism : the name of the used mechanism (KERBEROS_V4, ...)
+  * a credentials : bytes used to store the user's credentials
-    - name: The name of the directory object that the client wishes to
-      bind as.  This field may take on a null value (a zero length
-      string) for the purposes of anonymous binds, when authentication
-      has been performed at a lower layer, or when using SASL credentials
-      with a mechanism that includes the LDAPDN in the credentials.
  
-    - authentication: information used to authenticate the name, if any,
-      provided in the Bind Request.
+ __Control structure (if any):__
+  * a control type : the corresponding ["OID"]
+  * a criticality flag : used to tells the server how to handle the control
+  * a control value : the control's value 
  
+ Each structure is implemented as a Java Class.
+ 
+ == encoding the PDU ==
+ Now, we have to transform these Java classes to a ["PDU"]
+ 
+ First, here is the BindRequest Message we will use :
+ 
+ {{{
+ LdapMessage
+     message Id : 1
+     BindRequest
+         Version : '3'
+         Name : 'uid=akarasulu,dc=example,dc=com'
+         Simple authentication : 'password'
+ }}}
+ 
+ and here is the resulting ["PDU"] :
+ 
+ {{{
+ 0x30 0x33 
+   0x02 0x01 0x01 
+   0x60 0x2E 
+     0x02 0x01 0x03 
+     0x04 0x1F 0x75 0x69 0x64 0x3D 0x61 0x6B 0x61 0x72 0x61 0x73 0x75 0x6C 0x75 0x2C 0x64
0x63
+               0x3D 0x65 0x78 0x61 0x6D 0x70 0x6C 0x65 0x2C 0x64 0x63 0x3D 0x63 0x6F 0x6D

+     0x80 0x08 0x70 0x61 0x73 0x73 0x77 0x6F 0x72 0x64 
+ }}}
+ 
+ In the resulting ["PDU"], we have separated each primitive ["TLV"], so every line is a single
["TLV"].
+ 
+ We can represent the ["PDU"] structure with this schema :
+ 
+ attachment:BindRequestPDU.png
+ 
+ Th PDU has three levels of encapsulation. 
+  * The first level is a constructed ["TLV"], which length is 51 bytes. That is the Ldap``Message
envelope
+  * the second level is composed of two types of elements : Primitive types like Integer
(Version) and a Constructed Type : the Bind``Request
+  * The third level is the Bind``Request itself, composed of Primitive ["TLV"] only.
+ 
+ So we have only two constructed ["TLV"] in this sample : LdapMessage and Bind``Request.
+ 
+ === Computing the PDU length ===
+ We will have to store the encoded result in a Byte``Buffer, so we must compute its length
One could think that it's easy in this specific case, because '''L1''' is the total length
. This is not so simple.
+  * first, L1 is the length of the Value, so we need to add the T and L lengths
+  * second, even if valid for LdapMessages, this is not a general case. A PDU may be composed
of many successive ["PDU"]s, thus the first ["TLV"] length might not represents the total
size.
+ 
+ The best solution is to walk the structure and to compute each length. We have the following
relations :
+ 
+ {{{
+ PDU length = T1.length + L1.length + L1
+ L1 = T2.length + L2.length + L2 + T3.length + L3.length + L3
+ L2 = messageId.length
+ L3 = T4.length + L4.length + L4 + T5.length + L5.length + L5 + T6.length + L6.length + L6
+ L4 = version.length
+ L5 = name.length
+ L6 = authentication.simple.length
+ }}}
+ 
+ We can see that it's not possible to know L1 before having evaluated L2 and L3, and for
that we also need to compute L4, L5 and L6.
+ 
+ We cannot either dump bytes as soon as we have read the data from the JavaBean, because
we will have to update L1 and the end of the processing.
+ 
+ We have many possible strategies to solve this problem :
+  * use of a recursive approach
+  * use a standard approach, using transient values to store temporary computations.
+  * combine those two strategies
+ 
+ in conjonction with two possible ways to generate the bytes :
+  * construct the ["PDU"] using many Byte``Buffers and updating the cumulative lengths on
the fly
+  * construct the PDU by dumping computed lengths and values
+ 
+ The first solution leads to use a tree of temporary Byte``Buffers which will be assembled
before being sent, and is recursive.
+ The second solution need to first computes the length, and second to generate the full ["PDU"]
+ 
+ For many reasons, the second strategy has been adopted, as it's faster to implement, and
faster to execute.
+ 
+ So we will first compute the lengths by reordering the way lengths are calculated :
+ 
+ {{{
+ L2 = messageId.length
+ L4 = version.length
+ L5 = name.length
+ L6 = authentication.simple.length
+ 
+ L3 = T4.length + L4.length + L4 + T5.length + L5.length + L5 + T6.length + L6.length + L6
+ 
+ L1 = T2.length + L2.length + L2 + T3.length + L3.length + L3
+ 
+ PDU length = T1.length + L1.length + L1
+ }}}
+ 
+ First, we get all the primitive lengths, and store them in temporary variables.
+ Then we compute the Bind``Request length (L3), finishing with the LdapMessage length (L1),
finishing with the PDU length.
+ 
+ We are now able to allocate a Byte``Buffer which length will be equal to '''Pdu Length'''.
+ 
+ We will also store in each objects the computed values, to avoid a double evaluation. Here,
we will store a ''ldap``Message``Length'', and a ''bind``Request``Length'' (We will also store
internal lengths for Controls, if need)
+ 
+ This is a little bit over-splimplistic, in reallity, we ask the Bind``Request class to compute
its internal length. This is the reason why we have described the adopted solution as a combined
solution (recursive/linear)
+ 
+ === Generating the PDU ===
+ As soon as we have computed the ["PDU"]'s lengths, we can feed the Byte``Buffer.
+ 
+ We just have to respect the Grammar order :
+  1. a constructed ["TLV"] for the Ldap``Message envelope
+  1. the messageId
+  1. a constructed ["TLV"] for the Bind``Request envelope
+  1. the version
+  1. the name
+  1. the simple authentication
+ 
+ Note : we will ask the Bind``Request object to generate its bytes and to pour them into
the allocated Byte``Buffer.
+ 
+ That's it ! We now have a Byte``Buffer which is a ["PDU"]. MINA, it's up to you ...
+ 
+ = Conclusion =
+ The encoding process is simple. One who wants to implement an encoder has to be warned about
some tricks :
+  * String cannot be encoded as is. In Java, a String is encoded in Unicode, so special characters
cannot be stored in single bytes. To compute String's length, you *must* call the String.getBytes()
function. Then, you have to store the bytes, and use the length of this byte array to know
the real String's length, expressed in bytes. 
+  * you will have to store lengths, too. but if the Value is longer than 127 bytes, the length
part will not fit in a single byte. You will have to use a second byte, sometime a third or
a fourth one. Consider using the Length.getNbBytes( length ) and Length.getBytes( length )
methods to do so (the first one gives back the number of bytes, the second one generates the
bytes).
+  * if the Value part is null or empty, the length  will be 0. It has to be encoded.
+  
+ 

Mime
View raw message