/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2009 Sun Microsystems, Inc. */ package org.opends.sdk.ldap; import static com.sun.opends.sdk.messages.Messages.*; import static org.opends.sdk.asn1.ASN1Constants.*; import static com.sun.opends.sdk.ldap.LDAPConstants.*; import java.io.IOException; import java.util.logging.Level; import org.opends.sdk.*; import org.opends.sdk.asn1.ASN1Reader; import org.opends.sdk.controls.Control; import org.opends.sdk.requests.*; import org.opends.sdk.responses.*; import org.opends.sdk.sasl.GenericSASLBindRequest; import org.opends.sdk.schema.Schema; import com.sun.opends.sdk.util.StaticUtils; import com.sun.opends.sdk.ldap.LDAPMessageHandler; /** * Static methods for decoding LDAP messages. */ public class LDAPDecoder { /** * Decodes the elements from the provided ASN.1 reader as an LDAP * message. * * @param reader * The ASN.1 reader. * @param handler * The LDAPMessageHandler that will handle a * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ public static void decode(ASN1Reader reader, LDAPMessageHandler handler) throws IOException { reader.readStartSequence(); try { int messageID = (int) reader.readInteger(); decodeProtocolOp(reader, messageID, handler); } finally { reader.readEndSequence(); } } public static SearchResultEntry decodeEntry(ASN1Reader reader, Schema schema) throws IOException { SearchResultEntry message; reader.readStartSequence(OP_TYPE_SEARCH_RESULT_ENTRY); try { String dnString = reader.readOctetStringAsString(); DN dn; try { dn = DN.valueOf(dnString, schema); } catch (LocalizedIllegalArgumentException e) { throw DecodeException.error(e.getMessageObject()); } message = Responses.newSearchResultEntry(dn); reader.readStartSequence(); try { while (reader.hasNextElement()) { reader.readStartSequence(); try { String ads = reader.readOctetStringAsString(); AttributeDescription ad; try { ad = AttributeDescription.valueOf(ads, schema); } catch (LocalizedIllegalArgumentException e) { throw DecodeException.error(e.getMessageObject()); } Attribute attribute = new LinkedAttribute(ad); reader.readStartSet(); try { while (reader.hasNextElement()) { attribute.add(reader.readOctetString()); } message.addAttribute(attribute); } finally { reader.readEndSet(); } } finally { reader.readEndSequence(); } } } finally { reader.readEndSequence(); } } finally { reader.readEndSequence(); } return message; } /** * Decodes the elements from the provided ASN.1 read as an LDAP * abandon request protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeAbandonRequest(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { int msgToAbandon = (int) reader .readInteger(OP_TYPE_ABANDON_REQUEST); AbandonRequest message = Requests.newAbandonRequest(msgToAbandon); decodeControls(reader, message, messageID, handler); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP ABANDON REQUEST(messageID=%d, request=%s)", messageID, message)); } handler.handleAbandonRequest(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as an LDAP add * request protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeAddRequest(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { AddRequest message; ResolvedSchema resolvedSchema; reader.readStartSequence(OP_TYPE_ADD_REQUEST); try { String dnString = reader.readOctetStringAsString(); resolvedSchema = handler.resolveSchema(dnString); DN dn = resolvedSchema.getInitialDN(); message = Requests.newAddRequest(dn); reader.readStartSequence(); try { while (reader.hasNextElement()) { reader.readStartSequence(); try { String ads = reader.readOctetStringAsString(); AttributeDescription ad = resolvedSchema .decodeAttributeDescription(ads); Attribute attribute = new LinkedAttribute(ad); reader.readStartSet(); try { while (reader.hasNextElement()) { attribute.add(reader.readOctetString()); } message.addAttribute(attribute); } finally { reader.readEndSet(); } } finally { reader.readEndSequence(); } } } finally { reader.readEndSequence(); } } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler, resolvedSchema .getSchema()); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP ADD REQUEST(messageID=%d, request=%s)", messageID, message)); } handler.handleAddRequest(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as an add * response protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeAddResult(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { Result message; reader.readStartSequence(OP_TYPE_ADD_RESPONSE); try { ResultCode resultCode = ResultCode.valueOf(reader .readEnumerated()); String matchedDN = reader.readOctetStringAsString(); String diagnosticMessage = reader.readOctetStringAsString(); message = Responses.newResult(resultCode).setMatchedDN(matchedDN) .setDiagnosticMessage(diagnosticMessage); decodeResponseReferrals(reader, message); } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP ADD RESULT(messageID=%d, result=%s)", messageID, message)); } handler.handleAddResult(messageID, message); } /** * Decodes the elements from the provided ASN.1 read as an LDAP bind * request protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeBindRequest(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { reader.readStartSequence(OP_TYPE_BIND_REQUEST); try { int protocolVersion = (int) reader.readInteger(); String dnString = reader.readOctetStringAsString(); ResolvedSchema resolvedSchema = handler.resolveSchema(dnString); DN dn = resolvedSchema.getInitialDN(); byte type = reader.peekType(); switch (type) { case TYPE_AUTHENTICATION_SIMPLE: ByteString simplePassword = reader .readOctetString(TYPE_AUTHENTICATION_SIMPLE); SimpleBindRequest simpleBindMessage = Requests.newSimpleBindRequest(dn, simplePassword); decodeControls(reader, simpleBindMessage, messageID, handler, resolvedSchema.getSchema()); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG .finer(String .format( "DECODE LDAP BIND REQUEST(messageID=%d, auth=simple, request=%s)", messageID, simpleBindMessage)); } handler.handleBindRequest(messageID, protocolVersion, simpleBindMessage); break; case TYPE_AUTHENTICATION_SASL: String saslMechanism; ByteString saslCredentials; reader.readStartSequence(TYPE_AUTHENTICATION_SASL); try { saslMechanism = reader.readOctetStringAsString(); if (reader.hasNextElement() && (reader.peekType() == UNIVERSAL_OCTET_STRING_TYPE)) { saslCredentials = reader.readOctetString(); } else { saslCredentials = ByteString.empty(); } } finally { reader.readEndSequence(); } GenericSASLBindRequest rawSASLBindMessage = new GenericSASLBindRequest( saslMechanism, saslCredentials); // TODO: we can ignore the bind DN for SASL bind requests // according to the RFC. // // rawSASLBindMessage.setName(dn); decodeControls(reader, rawSASLBindMessage, messageID, handler, resolvedSchema.getSchema()); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG .finer(String .format( "DECODE LDAP BIND REQUEST(messageID=%d, auth=SASL, request=%s)", messageID, rawSASLBindMessage)); } handler.handleBindRequest(messageID, protocolVersion, rawSASLBindMessage); break; default: ByteString unknownAuthBytes = reader.readOctetString(type); GenericBindRequest rawUnknownBindMessage = Requests.newGenericBindRequest(dn, type, unknownAuthBytes); decodeControls(reader, rawUnknownBindMessage, messageID, handler, resolvedSchema.getSchema()); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG .finer(String .format( "DECODE LDAP BIND REQUEST(messageID=%d, auth=0x%x, request=%s)", messageID, rawUnknownBindMessage .getAuthenticationType(), rawUnknownBindMessage)); } handler.handleBindRequest(messageID, protocolVersion, rawUnknownBindMessage); } } finally { reader.readEndSequence(); } } /** * Decodes the elements from the provided ASN.1 reader as a bind * response protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeBindResult(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { BindResult message; reader.readStartSequence(OP_TYPE_BIND_RESPONSE); try { ResultCode resultCode = ResultCode.valueOf(reader .readEnumerated()); String matchedDN = reader.readOctetStringAsString(); String diagnosticMessage = reader.readOctetStringAsString(); message = Responses.newBindResult(resultCode).setMatchedDN(matchedDN) .setDiagnosticMessage(diagnosticMessage); decodeResponseReferrals(reader, message); if (reader.hasNextElement() && (reader.peekType() == TYPE_SERVER_SASL_CREDENTIALS)) { message.setServerSASLCredentials(reader .readOctetString(TYPE_SERVER_SASL_CREDENTIALS)); } } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP BIND RESULT(messageID=%d, result=%s)", messageID, message)); } handler.handleBindResult(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as an LDAP * compare request protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeCompareRequest(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { DN dn; AttributeDescription ad; ByteString assertionValue; ResolvedSchema resolvedSchema; reader.readStartSequence(OP_TYPE_COMPARE_REQUEST); try { String dnString = reader.readOctetStringAsString(); resolvedSchema = handler.resolveSchema(dnString); dn = resolvedSchema.getInitialDN(); reader.readStartSequence(); try { String ads = reader.readOctetStringAsString(); ad = resolvedSchema.decodeAttributeDescription(ads); assertionValue = reader.readOctetString(); } finally { reader.readEndSequence(); } } finally { reader.readEndSequence(); } CompareRequest message = Requests.newCompareRequest(dn, ad, assertionValue); decodeControls(reader, message, messageID, handler, resolvedSchema .getSchema()); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP COMPARE REQUEST(messageID=%d, request=%s)", messageID, message)); } handler.handleCompareRequest(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as a compare * response protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeCompareResult(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { CompareResult message; reader.readStartSequence(OP_TYPE_COMPARE_RESPONSE); try { ResultCode resultCode = ResultCode.valueOf(reader .readEnumerated()); String matchedDN = reader.readOctetStringAsString(); String diagnosticMessage = reader.readOctetStringAsString(); message = Responses.newCompareResult(resultCode).setMatchedDN(matchedDN) .setDiagnosticMessage(diagnosticMessage); decodeResponseReferrals(reader, message); } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP COMPARE RESULT(messageID=%d, result=%s)", messageID, message)); } handler.handleCompareResult(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as an LDAP * control. * * @param reader * The ASN.1 reader. * @param request * The decoded request to decode controls for. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will decode the * control. * @param schema * The schema to use when decoding control. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeControl(ASN1Reader reader, Request request, int messageID, LDAPMessageHandler handler, Schema schema) throws IOException { String oid; boolean isCritical; ByteString value; reader.readStartSequence(); try { oid = reader.readOctetStringAsString(); isCritical = false; value = null; if (reader.hasNextElement() && (reader.peekType() == UNIVERSAL_BOOLEAN_TYPE)) { isCritical = reader.readBoolean(); } if (reader.hasNextElement() && (reader.peekType() == UNIVERSAL_OCTET_STRING_TYPE)) { value = reader.readOctetString(); } } finally { reader.readEndSequence(); } try { Control c = handler.decodeRequestControl(messageID, oid, isCritical, value, schema); request.addControl(c); } catch (DecodeException e) { if (isCritical) { if (e.isFatal()) { throw DecodeException.error(e.getMessageObject(), e .getCause()); } else { // Exceptions encountered when decoding controls are never // fatal. throw e; } } } } /** * Decodes the elements from the provided ASN.1 reader as an LDAP * control. * * @param reader * The ASN.1 reader. * @param response * The decoded message to decode controls for. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will decode the * control. * @param schema * The schema to use when decoding control. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeControl(ASN1Reader reader, Response response, int messageID, LDAPMessageHandler handler, Schema schema) throws IOException { String oid; boolean isCritical; ByteString value; reader.readStartSequence(); try { oid = reader.readOctetStringAsString(); isCritical = false; value = null; if (reader.hasNextElement() && (reader.peekType() == UNIVERSAL_BOOLEAN_TYPE)) { isCritical = reader.readBoolean(); } if (reader.hasNextElement() && (reader.peekType() == UNIVERSAL_OCTET_STRING_TYPE)) { value = reader.readOctetString(); } } finally { reader.readEndSequence(); } try { Control c = handler.decodeResponseControl(messageID, oid, isCritical, value, schema); response.addControl(c); } catch (DecodeException e) { if (isCritical) { if (e.isFatal()) { throw DecodeException.error(e.getMessageObject(), e .getCause()); } else { // Exceptions encountered when decoding controls are never // fatal. throw e; } } } } /** * Decodes the elements from the provided ASN.1 reader as a set of * controls using the default schema. * * @param reader * The ASN.1 reader. * @param request * The decoded message to decode controls for. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will decode the * controls. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeControls(ASN1Reader reader, Request request, int messageID, LDAPMessageHandler handler) throws IOException { decodeControls(reader, request, messageID, handler, handler .getDefaultSchema()); } /** * Decodes the elements from the provided ASN.1 reader as a set of * controls. * * @param reader * The ASN.1 reader. * @param request * The decoded message to decode controls for. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will decode the * controls. * @param schema * The schema to use when decoding controls. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeControls(ASN1Reader reader, Request request, int messageID, LDAPMessageHandler handler, Schema schema) throws IOException { if (reader.hasNextElement() && (reader.peekType() == TYPE_CONTROL_SEQUENCE)) { reader.readStartSequence(TYPE_CONTROL_SEQUENCE); try { while (reader.hasNextElement()) { decodeControl(reader, request, messageID, handler, schema); } } finally { reader.readEndSequence(); } } } /** * Decodes the elements from the provided ASN.1 reader as a set of * controls using the default schema. * * @param reader * The ASN.1 reader. * @param response * The decoded message to decode controls for. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will decode the * controls. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeControls(ASN1Reader reader, Response response, int messageID, LDAPMessageHandler handler) throws IOException { decodeControls(reader, response, messageID, handler, handler .getDefaultSchema()); } /** * Decodes the elements from the provided ASN.1 reader as a set of * controls. * * @param reader * The ASN.1 reader. * @param response * The decoded message to decode controls for. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will decode the * controls. * @param schema * The schema to use when decoding control. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeControls(ASN1Reader reader, Response response, int messageID, LDAPMessageHandler handler, Schema schema) throws IOException { if (reader.hasNextElement() && (reader.peekType() == TYPE_CONTROL_SEQUENCE)) { reader.readStartSequence(TYPE_CONTROL_SEQUENCE); try { while (reader.hasNextElement()) { decodeControl(reader, response, messageID, handler, schema); } } finally { reader.readEndSequence(); } } } /** * Decodes the elements from the provided ASN.1 reader as an LDAP * delete request protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeDeleteRequest(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { String dnString = reader .readOctetStringAsString(OP_TYPE_DELETE_REQUEST); ResolvedSchema resolvedSchema = handler.resolveSchema(dnString); DN dn = resolvedSchema.getInitialDN(); DeleteRequest message = Requests.newDeleteRequest(dn); decodeControls(reader, message, messageID, handler, resolvedSchema .getSchema()); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP DELETE REQUEST(messageID=%d, request=%s)", messageID, message)); } handler.handleDeleteRequest(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as a delete * response protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeDeleteResult(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { Result message; reader.readStartSequence(OP_TYPE_DELETE_RESPONSE); try { ResultCode resultCode = ResultCode.valueOf(reader .readEnumerated()); String matchedDN = reader.readOctetStringAsString(); String diagnosticMessage = reader.readOctetStringAsString(); message = Responses.newResult(resultCode).setMatchedDN(matchedDN) .setDiagnosticMessage(diagnosticMessage); decodeResponseReferrals(reader, message); } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP DELETE RESULT(messageID=%d, result=%s)", messageID, message)); } handler.handleDeleteResult(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as an LDAP * extended request protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeExtendedRequest(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { String oid; ByteString value; reader.readStartSequence(OP_TYPE_EXTENDED_REQUEST); try { oid = reader.readOctetStringAsString(TYPE_EXTENDED_REQUEST_OID); value = null; if (reader.hasNextElement() && (reader.peekType() == TYPE_EXTENDED_REQUEST_VALUE)) { value = reader.readOctetString(TYPE_EXTENDED_REQUEST_VALUE); } } finally { reader.readEndSequence(); } GenericExtendedRequest message = Requests.newGenericExtendedRequest(oid, value); decodeControls(reader, message, messageID, handler); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP EXTENDED REQUEST(messageID=%d, request=%s)", messageID, message)); } handler.handleExtendedRequest(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as a extended * response protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeExtendedResult(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { GenericExtendedResult message; reader.readStartSequence(OP_TYPE_EXTENDED_RESPONSE); try { ResultCode resultCode = ResultCode.valueOf(reader .readEnumerated()); String matchedDN = reader.readOctetStringAsString(); String diagnosticMessage = reader.readOctetStringAsString(); message = Responses.newGenericExtendedResult(resultCode).setMatchedDN( matchedDN).setDiagnosticMessage(diagnosticMessage); decodeResponseReferrals(reader, message); if (reader.hasNextElement() && (reader.peekType() == TYPE_EXTENDED_RESPONSE_OID)) { message.setResponseName(reader .readOctetStringAsString(TYPE_EXTENDED_RESPONSE_OID)); } if (reader.hasNextElement() && (reader.peekType() == TYPE_EXTENDED_RESPONSE_VALUE)) { message.setResponseValue(reader .readOctetString(TYPE_EXTENDED_RESPONSE_VALUE)); } } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP EXTENDED RESULT(messageID=%d, result=%s)", messageID, message)); } handler.handleExtendedResult(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as an LDAP * intermediate response protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeIntermediateResponse(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { GenericIntermediateResponse message; reader.readStartSequence(OP_TYPE_INTERMEDIATE_RESPONSE); try { message = Responses.newGenericIntermediateResponse(); if (reader.hasNextElement() && (reader.peekType() == TYPE_INTERMEDIATE_RESPONSE_OID)) { message.setResponseName(reader .readOctetStringAsString(TYPE_INTERMEDIATE_RESPONSE_OID)); } if (reader.hasNextElement() && (reader.peekType() == TYPE_INTERMEDIATE_RESPONSE_VALUE)) { message.setResponseValue(reader .readOctetString(TYPE_INTERMEDIATE_RESPONSE_VALUE)); } } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG .finer(String .format( "DECODE LDAP INTERMEDIATE RESPONSE(messageID=%d, response=%s)", messageID, message)); } handler.handleIntermediateResponse(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as a modify DN * request protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeModifyDNRequest(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { ModifyDNRequest message; ResolvedSchema resolvedSchema; reader.readStartSequence(OP_TYPE_MODIFY_DN_REQUEST); try { String dnString = reader.readOctetStringAsString(); resolvedSchema = handler.resolveSchema(dnString); DN dn = resolvedSchema.getInitialDN(); String newRDNString = reader.readOctetStringAsString(); RDN newRDN = resolvedSchema.decodeRDN(newRDNString); message = Requests.newModifyDNRequest(dn, newRDN); message.setDeleteOldRDN(reader.readBoolean()); if (reader.hasNextElement() && (reader.peekType() == TYPE_MODIFY_DN_NEW_SUPERIOR)) { String newSuperiorString = reader .readOctetStringAsString(TYPE_MODIFY_DN_NEW_SUPERIOR); DN newSuperior = resolvedSchema.decodeDN(newSuperiorString); message.setNewSuperior(newSuperior); } } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler, resolvedSchema .getSchema()); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP MODIFY DN REQUEST(messageID=%d, request=%s)", messageID, message)); } handler.handleModifyDNRequest(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as a modify DN * response protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeModifyDNResult(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { Result message; reader.readStartSequence(OP_TYPE_MODIFY_DN_RESPONSE); try { ResultCode resultCode = ResultCode.valueOf(reader .readEnumerated()); String matchedDN = reader.readOctetStringAsString(); String diagnosticMessage = reader.readOctetStringAsString(); message = Responses.newResult(resultCode).setMatchedDN(matchedDN) .setDiagnosticMessage(diagnosticMessage); decodeResponseReferrals(reader, message); } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP MODIFY DN RESULT(messageID=%d, result=%s)", messageID, message)); } handler.handleModifyDNResult(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as an LDAP * modify request protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeModifyRequest(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { ModifyRequest message; ResolvedSchema resolvedSchema; reader.readStartSequence(OP_TYPE_MODIFY_REQUEST); try { String dnString = reader.readOctetStringAsString(); resolvedSchema = handler.resolveSchema(dnString); DN dn = resolvedSchema.getInitialDN(); message = Requests.newModifyRequest(dn); reader.readStartSequence(); try { while (reader.hasNextElement()) { reader.readStartSequence(); try { int typeIntValue = reader.readEnumerated(); ModificationType type = ModificationType .valueOf(typeIntValue); if (type == null) { throw DecodeException .error(ERR_LDAP_MODIFICATION_DECODE_INVALID_MOD_TYPE .get(typeIntValue)); } reader.readStartSequence(); try { String attributeDescription = reader .readOctetStringAsString(); Attribute attribute = new LinkedAttribute(resolvedSchema .decodeAttributeDescription(attributeDescription)); reader.readStartSet(); try { while (reader.hasNextElement()) { attribute.add(reader.readOctetString()); } message.addChange(new Change(type, attribute)); } finally { reader.readEndSet(); } } finally { reader.readEndSequence(); } } finally { reader.readEndSequence(); } } } finally { reader.readEndSequence(); } } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler, resolvedSchema .getSchema()); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP MODIFY REQUEST(messageID=%d, request=%s)", messageID, message)); } handler.handleModifyRequest(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as a modify * response protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeModifyResult(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { Result message; reader.readStartSequence(OP_TYPE_MODIFY_RESPONSE); try { ResultCode resultCode = ResultCode.valueOf(reader .readEnumerated()); String matchedDN = reader.readOctetStringAsString(); String diagnosticMessage = reader.readOctetStringAsString(); message = Responses.newResult(resultCode).setMatchedDN(matchedDN) .setDiagnosticMessage(diagnosticMessage); decodeResponseReferrals(reader, message); } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP MODIFY RESULT(messageID=%d, result=%s)", messageID, message)); } handler.handleModifyResult(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as an LDAP * protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeProtocolOp(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { byte type = reader.peekType(); switch (type) { case OP_TYPE_UNBIND_REQUEST: // 0x42 decodeUnbindRequest(reader, messageID, handler); break; case 0x43: // 0x43 case 0x44: // 0x44 case 0x45: // 0x45 case 0x46: // 0x46 case 0x47: // 0x47 case 0x48: // 0x48 case 0x49: // 0x49 handler.handleUnrecognizedMessage(messageID, type, reader .readOctetString(type)); break; case OP_TYPE_DELETE_REQUEST: // 0x4A decodeDeleteRequest(reader, messageID, handler); break; case 0x4B: // 0x4B case 0x4C: // 0x4C case 0x4D: // 0x4D case 0x4E: // 0x4E case 0x4F: // 0x4F handler.handleUnrecognizedMessage(messageID, type, reader .readOctetString(type)); break; case OP_TYPE_ABANDON_REQUEST: // 0x50 decodeAbandonRequest(reader, messageID, handler); break; case 0x51: // 0x51 case 0x52: // 0x52 case 0x53: // 0x53 case 0x54: // 0x54 case 0x55: // 0x55 case 0x56: // 0x56 case 0x57: // 0x57 case 0x58: // 0x58 case 0x59: // 0x59 case 0x5A: // 0x5A case 0x5B: // 0x5B case 0x5C: // 0x5C case 0x5D: // 0x5D case 0x5E: // 0x5E case 0x5F: // 0x5F handler.handleUnrecognizedMessage(messageID, type, reader .readOctetString(type)); break; case OP_TYPE_BIND_REQUEST: // 0x60 decodeBindRequest(reader, messageID, handler); break; case OP_TYPE_BIND_RESPONSE: // 0x61 decodeBindResult(reader, messageID, handler); break; case 0x62: // 0x62 handler.handleUnrecognizedMessage(messageID, type, reader .readOctetString(type)); break; case OP_TYPE_SEARCH_REQUEST: // 0x63 decodeSearchRequest(reader, messageID, handler); break; case OP_TYPE_SEARCH_RESULT_ENTRY: // 0x64 decodeSearchResultEntry(reader, messageID, handler); break; case OP_TYPE_SEARCH_RESULT_DONE: // 0x65 decodeSearchResult(reader, messageID, handler); break; case OP_TYPE_MODIFY_REQUEST: // 0x66 decodeModifyRequest(reader, messageID, handler); break; case OP_TYPE_MODIFY_RESPONSE: // 0x67 decodeModifyResult(reader, messageID, handler); break; case OP_TYPE_ADD_REQUEST: // 0x68 decodeAddRequest(reader, messageID, handler); break; case OP_TYPE_ADD_RESPONSE: // 0x69 decodeAddResult(reader, messageID, handler); break; case 0x6A: // 0x6A handler.handleUnrecognizedMessage(messageID, type, reader .readOctetString(type)); break; case OP_TYPE_DELETE_RESPONSE: // 0x6B decodeDeleteResult(reader, messageID, handler); break; case OP_TYPE_MODIFY_DN_REQUEST: // 0x6C decodeModifyDNRequest(reader, messageID, handler); break; case OP_TYPE_MODIFY_DN_RESPONSE: // 0x6D decodeModifyDNResult(reader, messageID, handler); break; case OP_TYPE_COMPARE_REQUEST: // 0x6E decodeCompareRequest(reader, messageID, handler); break; case OP_TYPE_COMPARE_RESPONSE: // 0x6F decodeCompareResult(reader, messageID, handler); break; case 0x70: // 0x70 case 0x71: // 0x71 case 0x72: // 0x72 handler.handleUnrecognizedMessage(messageID, type, reader .readOctetString(type)); break; case OP_TYPE_SEARCH_RESULT_REFERENCE: // 0x73 decodeSearchResultReference(reader, messageID, handler); break; case 0x74: // 0x74 case 0x75: // 0x75 case 0x76: // 0x76 handler.handleUnrecognizedMessage(messageID, type, reader .readOctetString(type)); break; case OP_TYPE_EXTENDED_REQUEST: // 0x77 decodeExtendedRequest(reader, messageID, handler); break; case OP_TYPE_EXTENDED_RESPONSE: // 0x78 decodeExtendedResult(reader, messageID, handler); break; case OP_TYPE_INTERMEDIATE_RESPONSE: // 0x79 decodeIntermediateResponse(reader, messageID, handler); break; default: handler.handleUnrecognizedMessage(messageID, type, reader .readOctetString(type)); break; } } private static void decodeResponseReferrals(ASN1Reader reader, Result message) throws IOException { if (reader.hasNextElement() && (reader.peekType() == TYPE_REFERRAL_SEQUENCE)) { reader.readStartSequence(TYPE_REFERRAL_SEQUENCE); try { // Should have at least 1. do { message.addReferralURI((reader.readOctetStringAsString())); } while (reader.hasNextElement()); } finally { reader.readEndSequence(); } } } /** * Decodes the elements from the provided ASN.1 reader as a search * result done protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeSearchResult(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { Result message; reader.readStartSequence(OP_TYPE_SEARCH_RESULT_DONE); try { ResultCode resultCode = ResultCode.valueOf(reader .readEnumerated()); String matchedDN = reader.readOctetStringAsString(); String diagnosticMessage = reader.readOctetStringAsString(); message = Responses.newResult(resultCode).setMatchedDN(matchedDN) .setDiagnosticMessage(diagnosticMessage); decodeResponseReferrals(reader, message); } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP SEARCH RESULT(messageID=%d, result=%s)", messageID, message)); } handler.handleSearchResult(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as an LDAP * search result entry protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeSearchResultEntry(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { SearchResultEntry message; ResolvedSchema resolvedSchema; reader.readStartSequence(OP_TYPE_SEARCH_RESULT_ENTRY); try { String dnString = reader.readOctetStringAsString(); resolvedSchema = handler.resolveSchema(dnString); DN dn = resolvedSchema.getInitialDN(); message = Responses.newSearchResultEntry(dn); reader.readStartSequence(); try { while (reader.hasNextElement()) { reader.readStartSequence(); try { String ads = reader.readOctetStringAsString(); AttributeDescription ad = resolvedSchema .decodeAttributeDescription(ads); Attribute attribute = new LinkedAttribute(ad); reader.readStartSet(); try { while (reader.hasNextElement()) { attribute.add(reader.readOctetString()); } message.addAttribute(attribute); } finally { reader.readEndSet(); } } finally { reader.readEndSequence(); } } } finally { reader.readEndSequence(); } } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler, resolvedSchema .getSchema()); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP SEARCH RESULT ENTRY(messageID=%d, entry=%s)", messageID, message)); } handler.handleSearchResultEntry(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as a search * result reference protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeSearchResultReference(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { SearchResultReference message; reader.readStartSequence(OP_TYPE_SEARCH_RESULT_REFERENCE); try { message = Responses.newSearchResultReference(reader .readOctetStringAsString()); while (reader.hasNextElement()) { message.addURI(reader.readOctetStringAsString()); } } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG .finer(String .format( "DECODE LDAP SEARCH RESULT REFERENCE(messageID=%d, reference=%s)", messageID, message)); } handler.handleSearchResultReference(messageID, message); } /** * Decodes the elements from the provided ASN.1 reader as an LDAP * search request protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeSearchRequest(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { SearchRequest message; ResolvedSchema resolvedSchema; reader.readStartSequence(OP_TYPE_SEARCH_REQUEST); try { String baseDNString = reader.readOctetStringAsString(); resolvedSchema = handler.resolveSchema(baseDNString); DN baseDN = resolvedSchema.getInitialDN(); int scopeIntValue = reader.readEnumerated(); SearchScope scope = SearchScope.valueOf(scopeIntValue); if (scope == null) { throw DecodeException .error(ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_SCOPE .get(scopeIntValue)); } int dereferencePolicyIntValue = reader.readEnumerated(); DereferenceAliasesPolicy dereferencePolicy = DereferenceAliasesPolicy .valueOf(dereferencePolicyIntValue); if (dereferencePolicy == null) { throw DecodeException .error(ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_DEREF .get(dereferencePolicyIntValue)); } int sizeLimit = (int) reader.readInteger(); int timeLimit = (int) reader.readInteger(); boolean typesOnly = reader.readBoolean(); Filter filter = LDAPUtils.decodeFilter(reader); message = Requests.newSearchRequest(baseDN, scope, filter); message.setDereferenceAliasesPolicy(dereferencePolicy); try { message.setTimeLimit(timeLimit); message.setSizeLimit(sizeLimit); } catch (LocalizedIllegalArgumentException e) { throw DecodeException.error(e.getMessageObject()); } message.setTypesOnly(typesOnly); reader.readStartSequence(); try { while (reader.hasNextElement()) { message.addAttribute(reader.readOctetStringAsString()); } } finally { reader.readEndSequence(); } } finally { reader.readEndSequence(); } decodeControls(reader, message, messageID, handler, resolvedSchema .getSchema()); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP SEARCH REQUEST(messageID=%d, request=%s)", messageID, message)); } handler.handleSearchRequest(messageID, message); } /** * Decodes the elements from the provided ASN.1 read as an LDAP unbind * request protocol op. * * @param reader * The ASN.1 reader. * @param messageID * The decoded message ID for this message. * @param handler * The LDAPMessageHandler that will handle this * decoded message. * @throws IOException * If an error occurred while reading bytes to decode. */ private static void decodeUnbindRequest(ASN1Reader reader, int messageID, LDAPMessageHandler handler) throws IOException { UnbindRequest message; reader.readNull(OP_TYPE_UNBIND_REQUEST); message = Requests.newUnbindRequest(); decodeControls(reader, message, messageID, handler); if (StaticUtils.DEBUG_LOG.isLoggable(Level.FINER)) { StaticUtils.DEBUG_LOG.finer(String.format( "DECODE LDAP UNBIND REQUEST(messageID=%d, request=%s)", messageID, message)); } handler.handleUnbindRequest(messageID, message); } }