pingidentity / ldapsdk

UnboundID LDAP SDK for Java
Other
327 stars 79 forks source link

JNDIExtendedRequest.getEncodedValue and JNDIExtendedResponse construct both expect Elements types when they might not exist #130

Open buksvdl opened 2 years ago

buksvdl commented 2 years ago

Hi, JNDIExtendedRequest public byte[] getEncodedValue() { final ASN1OctetString value = r.getValue(); if (value == null) { return null; } else { return value.encode(); } }

should return value.getValue();

Similarly `JNDIExtendedResponse(@Nullable final String id, @Nullable final byte[] berValue, final int offset, final int length) throws NamingException { final ASN1OctetString value; if (berValue == null) { value = null; } else { try { if ((offset == 0) && (length == berValue.length)) { value = ASN1OctetString.decodeAsOctetString(berValue); } else { final byte[] valueBytes = new byte[length]; System.arraycopy(berValue, offset, valueBytes, 0, length); value = ASN1OctetString.decodeAsOctetString(valueBytes); } } catch (final ASN1Exception ae) { throw new NamingException(StaticUtils.getExceptionMessage(ae)); } }

r = new ExtendedResult(-1, ResultCode.SUCCESS, null, null, null, id, value,
                       null);

}`

should construct a value of Elements ExtendedResult extendedResult = new ExtendedResult( -1, ResultCode.SUCCESS, null, null, null, id, new ASN1OctetString( new ASN1Sequence( List.of( ASN1Element.decode(value.getValue()) ) ).encode() ), null);

dirmgr commented 2 years ago

The Javadoc for the javax.naming.ldap.ExtendedRequest.getEncodedValue() method states "The result is the raw BER bytes including the tag and length of the request value.". This indicates that value.encode() is correct, and value.getValue() is not.

Also, I really don't understand what you're trying to say about the JNDIExtendedResponse constructor, but I believe the implementation is correct as written. The documentation for that constructor states that the berValue byte array should represent the encoded value (including the BER type and length), and that corresponds to the documented behavior of the javax.naming.ldap.ExtendedResponse.getEncodedValue() method.

buksvdl commented 2 years ago

My case is built around PasswordModifyExtendedRequest/Result.

javax.naming.ldap.ExtendedRequest public ExtendedResponse createExtendedResponse(String id, byte[] berValue, int offset, int length) throws NamingException;

The berValue received here is a ASN1OctetString with type 48(Element) which in turn represents a type -128 String(The password)

password = ASN1Element.decode(value.getValue()).decodeAsOctetString().stringValue()

constructing the Unbound ExtendedResult the expected value is an ASN1OctetString type 4(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE) containing a sequence type 48(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE) of Elements of type -128 mapped to a ASN1OctetString(The generatedPassword)

If you leave the current code you will never get to the generated password.

buksvdl commented 2 years ago

As for the request. The ExtendedRequest constructor already encodes the complete request new ASN1OctetString(new ASN1Sequence(elements).encode());

dirmgr commented 2 years ago

After testing, it does appear that the behavior that JNDI actually exhibits directly contradicts its documentation. This appears to be true for extended requests, extended responses, and controls.

I have just committed a change that updates the LDAP SDK's JNDI migration support so that it uses the behavior that JNDI actually exhibits rather than what it is documented to do. In the event that there is an implementation that actually does conform to the documentation, it's possible to get the former behavior through the use of system properties.