You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@directory.apache.org by Van Nhu <va...@yahoo.com> on 2005/11/23 07:34:27 UTC
The Twix Codec for LDAP Controls
Hi all,
According to the RFC 2251, the "controlType" attribute
of an LDAP Control "...MUST be a UTF-8 encoded
dotted-decimal representation of an OBJECT IDENTIFIER
which uniquely identifies the control". Essentially,
this means that the "controlType" attribute is an
OCTET STRING and should be treated as such.
However, the Twix ASN1 codec is treating this
attribute as an OBJECT IDENTIFIER. This results in
incorrect decoding/decoding of LDAP Controls.
I suggest that we change the type of the "controlType"
attribute of the org.apache.asn1new.ldap.pojo.Control
class from OID to LdapString to fix the problem. A
patch, which includes a test for exposing the problem
and validating the fix, is attached for your
reference.
With Regards,
Van
__________________________________
Yahoo! FareChase: Search multiple travel sites in one click.
http://farechase.yahoo.com
Re: The Twix Codec for LDAP Controls
Posted by Emmanuel Lécharny <el...@iktek.com>.
Ok, I now get it.
The confusion between Octet String and Object Identifier has been done
when I was working on SPNEGO protocol, which use Object Identifier (tag
0x06) when Ldap use 0x04.
I will correct the code this afternoon to deal with this problem.
Thanks for the junit test and for the report, Van !
-- Emmanuel
Re: The Twix Codec for LDAP Controls
Posted by Emmanuel Lécharny <el...@iktek.com>.
The problem has been fixed.
Thanks a lot Van !
Could you just enter a JIRA issue the next time you find a problem, it
will be easier to keep a track on it.
Re: The Twix Codec for LDAP Controls
Posted by Emmanuel Lecharny <el...@apache.org>.
Hi !
Thanks a lot for this report !
I don't get your point about the LdapString. The controlType is an
LDAPOID, which is internally an OctetString. Changing it to a LdapString
won't change anything, because this controltype will always be something
like :
1.3.6.1.4... and nothing else.
The OID class is just a way to store an internal representation of an
OID (btw, not sure that storing an oid as a array of integer is the best
solution ;)
I saw that there is a problem while using your test with the actual
encoding system, but I'm not sure it is related to the fact the
controlType is not a LdapString.
Give me some time to check it, I will send you a full answer in a few
hours.
-- Emmanuel
On Tue, 2005-11-22 at 22:34 -0800, Van Nhu wrote:
> Hi all,
>
> According to the RFC 2251, the "controlType" attribute
> of an LDAP Control "...MUST be a UTF-8 encoded
> dotted-decimal representation of an OBJECT IDENTIFIER
> which uniquely identifies the control". Essentially,
> this means that the "controlType" attribute is an
> OCTET STRING and should be treated as such.
>
> However, the Twix ASN1 codec is treating this
> attribute as an OBJECT IDENTIFIER. This results in
> incorrect decoding/decoding of LDAP Controls.
>
> I suggest that we change the type of the "controlType"
> attribute of the org.apache.asn1new.ldap.pojo.Control
> class from OID to LdapString to fix the problem. A
> patch, which includes a test for exposing the problem
> and validating the fix, is attached for your
> reference.
>
> With Regards,
> Van
>
>
>
> __________________________________
> Yahoo! FareChase: Search multiple travel sites in one click.
> http://farechase.yahoo.com
> ---------------------------------------------------------------------------------------
> Wanadoo vous informe que cet e-mail a ete controle par l'anti-virus mail.
> Aucun virus connu a ce jour par nos services n'a ete detecte.
>
> plain text document attachment (LDAPControlCodec.patch), "4069829843-
> LDAPControlCodec.patch"
> Index: apache2-provider/src/test/org/apache/asn1new/ldap/codec/SearchRequestTest.java
> ===================================================================
> --- apache2-provider/src/test/org/apache/asn1new/ldap/codec/SearchRequestTest.java (revision 348378)
> +++ apache2-provider/src/test/org/apache/asn1new/ldap/codec/SearchRequestTest.java (working copy)
> @@ -29,6 +29,7 @@
> import org.apache.asn1new.ldap.pojo.AttributeValueAssertion;
> import org.apache.asn1new.ldap.pojo.LdapMessage;
> import org.apache.asn1new.ldap.pojo.SearchRequest;
> +import org.apache.asn1new.ldap.pojo.Control;
> import org.apache.asn1new.ldap.pojo.filters.AndFilter;
> import org.apache.asn1new.ldap.pojo.filters.AttributeValueAssertionFilter;
> import org.apache.asn1new.ldap.pojo.filters.NotFilter;
> @@ -46,7 +47,105 @@
> * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
> */
> public class SearchRequestTest extends TestCase {
> +
> /**
> + * Test the decoding of a SearchRequest with controls.
> + */
> + public void testDecodeSearchRequestWithControls()
> + {
> + byte[] asn1BER = new byte[]
> + {
> + 0x30, 0x7f,
> + 0x02, 0x01, 0x04, // messageID
> + 0x63, 0x33,
> + 0x04, 0x13,
> + 0x64, 0x63, 0x3d, 0x6d, 0x79, 0x2d, 0x64, 0x6f, 0x6d, 0x61,
> + 0x69, 0x6e, 0x2c, 0x64, 0x63, 0x3d, 0x63, 0x6f, 0x6d, // baseObject: dc=my-domain,dc=com
> + 0x0a, 0x01, 0x02, // scope: subtree
> + 0x0a, 0x01, 0x03, // derefAliases: derefAlways
> + 0x02, 0x01, 0x00, // sizeLimit: 0
> + 0x02, 0x01, 0x00, // timeLimit: 0
> + 0x01, 0x01, 0x00, // typesOnly: false
> + (byte)0x87, 0x0b,
> + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x6c, 0x61, 0x73, 0x73, // filter: (objectClass=*)
> + 0x30, 0x00,
> + (byte)0xa0, 0x45, // controls
> + 0x30, 0x28,
> + 0x04, 0x16,
> + 0x31, 0x2e, 0x32, 0x2e, 0x38, 0x34, 0x30, 0x2e, 0x31, 0x31,
> + 0x33, 0x35, 0x35, 0x36, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x33,
> + 0x31, 0x39, // control oid: 1.2.840.113556.1.4.319
> + 0x01, 0x01, (byte)0xff, // criticality: false
> + 0x04, 0x0b,
> + 0x30, 0x09, 0x02, 0x01, 0x02, 0x04, 0x04, 0x47, 0x00, 0x00, 0x00, // value: pageSize=2
> + 0x30, 0x19,
> + 0x04, 0x17,
> + 0x32, 0x2e, 0x31, 0x36, 0x2e, 0x38, 0x34, 0x30, 0x2e, 0x31,
> + 0x2e, 0x31, 0x31, 0x33, 0x37, 0x33, 0x30, 0x2e, 0x33, 0x2e,
> + 0x34, 0x2e, 0x32 // control oid: 2.16.840.1.113730.3.4.2
> + };
> +
> + Asn1Decoder ldapDecoder = new LdapDecoder();
> +
> + ByteBuffer stream = ByteBuffer.allocate( asn1BER.length );
> + stream.put( asn1BER );
> + String decodedPdu = StringUtils.dumpBytes( stream.array() );
> + stream.flip();
> +
> + IAsn1Container ldapMessageContainer = new LdapMessageContainer();
> +
> + try
> + {
> + ldapDecoder.decode( stream, ldapMessageContainer );
> + }
> + catch ( DecoderException de )
> + {
> + de.printStackTrace();
> + Assert.fail( de.getMessage() );
> + }
> +
> + LdapMessage message = ( ( LdapMessageContainer ) ldapMessageContainer ).getLdapMessage();
> + Assert.assertEquals( 4, message.getMessageId() );
> + Assert.assertEquals( 2, message.getControls().size() );
> +
> + // this is a constant in Java 5 API
> + String pagedResultsControlOID = "1.2.840.113556.1.4.319";
> + Control pagedResultsControl = message.getControls( 0 );
> + Assert.assertEquals( pagedResultsControlOID, pagedResultsControl.getControlType() );
> + Assert.assertTrue( pagedResultsControl.getCriticality() );
> +
> + // this is a constant in Java 5 API
> + String manageReferralControlOID = "2.16.840.1.113730.3.4.2";
> + Control manageReferralControl = message.getControls( 1 );
> + Assert.assertEquals( manageReferralControlOID, manageReferralControl.getControlType() );
> +
> + SearchRequest sr = message.getSearchRequest();
> + Assert.assertEquals( "dc=my-domain,dc=com", sr.getBaseObject() );
> + Assert.assertEquals( LdapConstants.SCOPE_WHOLE_SUBTREE, sr.getScope() );
> + Assert.assertEquals( LdapConstants.DEREF_ALWAYS, sr.getDerefAliases() );
> + Assert.assertEquals( 0, sr.getSizeLimit() );
> + Assert.assertEquals( 0, sr.getTimeLimit() );
> + Assert.assertEquals( false, sr.isTypesOnly() );
> +
> + Assert.assertTrue( sr.getFilter() instanceof PresentFilter );
> + Assert.assertEquals ( "objectClass",
> + ( (PresentFilter) sr.getFilter() ).getAttributeDescription().getString());
> +
> + // Check the encoding
> + try
> + {
> + ByteBuffer bb = message.encode( null );
> + String encodedPdu = StringUtils.dumpBytes( bb.array() );
> + Assert.assertEquals(encodedPdu, decodedPdu );
> + }
> + catch ( EncoderException ee )
> + {
> + ee.printStackTrace();
> + Assert.fail( ee.getMessage() );
> + }
> + }
> +
> + /**
> * Test the decoding of a SearchRequest with no controls.
> * The search filter is :
> * (&(|(objectclass=top)(ou=contacts))(!(objectclass=ttt)))
> Index: apache2-provider/src/main/java/org/apache/asn1new/ldap/pojo/Control.java
> ===================================================================
> --- apache2-provider/src/main/java/org/apache/asn1new/ldap/pojo/Control.java (revision 348378)
> +++ apache2-provider/src/main/java/org/apache/asn1new/ldap/pojo/Control.java (working copy)
> @@ -20,11 +20,11 @@
> import java.nio.ByteBuffer;
>
> import org.apache.asn1new.Asn1Object;
> +import org.apache.asn1new.ldap.codec.primitives.LdapString;
> import org.apache.asn1.codec.EncoderException;
> import org.apache.asn1new.ber.tlv.Length;
> import org.apache.asn1new.ber.tlv.UniversalTag;
> import org.apache.asn1new.ber.tlv.Value;
> -import org.apache.asn1new.primitives.OID;
> import org.apache.asn1.codec.util.StringUtils;
>
>
> @@ -37,8 +37,12 @@
> {
> //~ Instance fields ----------------------------------------------------------------------------
>
> - /** The control type */
> - private OID controlType;
> + /**
> + * The control type as an UTF-8 encoded dotted-decimal
> + * representation of an OBJECT IDENTIFIER which uniquely
> + * identifies the control
> + */
> + private LdapString controlType;
>
> /** The criticality (default value is false) */
> private boolean criticality = false;
> @@ -68,7 +72,7 @@
> *
> * @param controlType An OID to store
> */
> - public void setControlType( OID controlType )
> + public void setControlType( LdapString controlType )
> {
> this.controlType = controlType;
> }
> @@ -143,7 +147,7 @@
> public int computeLength()
> {
> // The controlType
> - int controlTypeLengh = controlType.getOIDLength();
> + int controlTypeLengh = controlType.getNbBytes();
> controlLength = 1 + Length.getNbBytes( controlTypeLengh ) + controlTypeLengh;
>
> // The criticality, only if true
> @@ -190,7 +194,7 @@
> }
>
> // The control type
> - Value.encode( buffer, controlType );
> + Value.encode( buffer, controlType.getBytes() );
>
> // The control criticality, if true
> if ( criticality == true )
> Index: apache2-provider/src/main/java/org/apache/asn1new/ldap/codec/grammar/LdapControlGrammar.java
> ===================================================================
> --- apache2-provider/src/main/java/org/apache/asn1new/ldap/codec/grammar/LdapControlGrammar.java (revision 348378)
> +++ apache2-provider/src/main/java/org/apache/asn1new/ldap/codec/grammar/LdapControlGrammar.java (working copy)
> @@ -28,9 +28,10 @@
> import org.apache.asn1new.util.BooleanDecoder;
> import org.apache.asn1new.util.BooleanDecoderException;
> import org.apache.asn1.codec.util.StringUtils;
> -import org.apache.asn1new.primitives.OID;
> import org.apache.asn1new.ldap.codec.LdapConstants;
> import org.apache.asn1new.ldap.codec.LdapMessageContainer;
> +import org.apache.asn1new.ldap.codec.primitives.LdapString;
> +import org.apache.asn1new.ldap.codec.primitives.LdapStringEncodingException;
> import org.apache.asn1new.ldap.pojo.Control;
> import org.apache.asn1new.ldap.pojo.LdapMessage;
> import org.slf4j.Logger;
> @@ -189,7 +190,15 @@
> }
> else
> {
> - control.setControlType( new OID( tlv.getValue().getData() ) );
> + try
> + {
> + control.setControlType( new LdapString(tlv.getValue().getData() ) );
> + }
> + catch (LdapStringEncodingException e)
> + {
> + log.error( "Error encoding control type", e );
> + throw new DecoderException( "Error encoding control type: " + e );
> + }
> }
>
> if ( log.isDebugEnabled() )