001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2009 Sun Microsystems, Inc. 025 * Portions copyright 2011-2013 ForgeRock AS 026 */ 027 028package org.forgerock.opendj.io; 029 030import static com.forgerock.opendj.ldap.CoreMessages.*; 031 032import java.io.IOException; 033 034import org.forgerock.i18n.LocalizedIllegalArgumentException; 035import org.forgerock.i18n.slf4j.LocalizedLogger; 036import org.forgerock.opendj.ldap.Attribute; 037import org.forgerock.opendj.ldap.AttributeDescription; 038import org.forgerock.opendj.ldap.ByteString; 039import org.forgerock.opendj.ldap.DN; 040import org.forgerock.opendj.ldap.DecodeException; 041import org.forgerock.opendj.ldap.DecodeOptions; 042import org.forgerock.opendj.ldap.DereferenceAliasesPolicy; 043import org.forgerock.opendj.ldap.Entry; 044import org.forgerock.opendj.ldap.Filter; 045import org.forgerock.opendj.ldap.Modification; 046import org.forgerock.opendj.ldap.ModificationType; 047import org.forgerock.opendj.ldap.RDN; 048import org.forgerock.opendj.ldap.ResultCode; 049import org.forgerock.opendj.ldap.SearchScope; 050import org.forgerock.opendj.ldap.controls.Control; 051import org.forgerock.opendj.ldap.controls.GenericControl; 052import org.forgerock.opendj.ldap.requests.AbandonRequest; 053import org.forgerock.opendj.ldap.requests.AddRequest; 054import org.forgerock.opendj.ldap.requests.CompareRequest; 055import org.forgerock.opendj.ldap.requests.DeleteRequest; 056import org.forgerock.opendj.ldap.requests.GenericBindRequest; 057import org.forgerock.opendj.ldap.requests.GenericExtendedRequest; 058import org.forgerock.opendj.ldap.requests.ModifyDNRequest; 059import org.forgerock.opendj.ldap.requests.ModifyRequest; 060import org.forgerock.opendj.ldap.requests.Request; 061import org.forgerock.opendj.ldap.requests.Requests; 062import org.forgerock.opendj.ldap.requests.SearchRequest; 063import org.forgerock.opendj.ldap.requests.UnbindRequest; 064import org.forgerock.opendj.ldap.responses.BindResult; 065import org.forgerock.opendj.ldap.responses.CompareResult; 066import org.forgerock.opendj.ldap.responses.GenericExtendedResult; 067import org.forgerock.opendj.ldap.responses.GenericIntermediateResponse; 068import org.forgerock.opendj.ldap.responses.Response; 069import org.forgerock.opendj.ldap.responses.Responses; 070import org.forgerock.opendj.ldap.responses.Result; 071import org.forgerock.opendj.ldap.responses.SearchResultEntry; 072import org.forgerock.opendj.ldap.responses.SearchResultReference; 073import org.forgerock.opendj.ldap.schema.Schema; 074 075/** 076 * Reads LDAP messages from an underlying ASN.1 reader. 077 * 078 * @param <R> 079 * The type of ASN.1 reader used for decoding elements. 080 */ 081public final class LDAPReader<R extends ASN1Reader> { 082 083 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 084 085 private final DecodeOptions options; 086 private final R reader; 087 088 LDAPReader(final R asn1Reader, final DecodeOptions options) { 089 this.reader = asn1Reader; 090 this.options = options; 091 } 092 093 /** 094 * Returns the ASN.1 reader from which LDAP messages will be read. 095 * 096 * @return The ASN.1 reader from which LDAP messages will be read. 097 */ 098 public R getASN1Reader() { 099 return reader; 100 } 101 102 /** 103 * Returns {@code true} if the next LDAP message can be read without 104 * blocking. 105 * 106 * @return {@code true} if the next LDAP message can be read without 107 * blocking or {@code false} otherwise. 108 * @throws DecodeException 109 * If the available data was not a valid LDAP message. 110 * @throws IOException 111 * If an unexpected IO error occurred. 112 */ 113 public boolean hasMessageAvailable() throws DecodeException, IOException { 114 return reader.elementAvailable(); 115 } 116 117 /** 118 * Reads the next LDAP message from the underlying ASN.1 reader. 119 * 120 * @param handler 121 * The message handler which will handle the decoded LDAP 122 * message. 123 * @throws DecodeException 124 * If the available data was not a valid LDAP message. 125 * @throws IOException 126 * If an unexpected IO error occurred. 127 */ 128 public void readMessage(final LDAPMessageHandler handler) throws DecodeException, IOException { 129 reader.readStartSequence(); 130 try { 131 final int messageID = (int) reader.readInteger(); 132 readProtocolOp(messageID, handler); 133 } finally { 134 reader.readEndSequence(); 135 } 136 } 137 138 private void readAbandonRequest(final int messageID, final LDAPMessageHandler handler) 139 throws IOException { 140 final int msgToAbandon = (int) reader.readInteger(LDAP.OP_TYPE_ABANDON_REQUEST); 141 final AbandonRequest message = Requests.newAbandonRequest(msgToAbandon); 142 readControls(message); 143 logger.trace("DECODE LDAP ABANDON REQUEST(messageID=%d, request=%s)", messageID, message); 144 handler.abandonRequest(messageID, message); 145 } 146 147 private void readAddRequest(final int messageID, final LDAPMessageHandler handler) 148 throws IOException { 149 final Entry entry = LDAP.readEntry(reader, LDAP.OP_TYPE_ADD_REQUEST, options); 150 final AddRequest message = Requests.newAddRequest(entry); 151 readControls(message); 152 logger.trace("DECODE LDAP ADD REQUEST(messageID=%d, request=%s)", messageID, message); 153 handler.addRequest(messageID, message); 154 } 155 156 private void readAddResult(final int messageID, final LDAPMessageHandler handler) 157 throws IOException { 158 reader.readStartSequence(LDAP.OP_TYPE_ADD_RESPONSE); 159 final Result message; 160 try { 161 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 162 final String matchedDN = reader.readOctetStringAsString(); 163 final String diagnosticMessage = reader.readOctetStringAsString(); 164 message = 165 Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( 166 diagnosticMessage); 167 readResponseReferrals(message); 168 } finally { 169 reader.readEndSequence(); 170 } 171 readControls(message); 172 logger.trace("DECODE LDAP ADD RESULT(messageID=%d, result=%s)", messageID, message); 173 handler.addResult(messageID, message); 174 } 175 176 private void readBindRequest(final int messageID, final LDAPMessageHandler handler) 177 throws IOException { 178 reader.readStartSequence(LDAP.OP_TYPE_BIND_REQUEST); 179 try { 180 final int protocolVersion = (int) reader.readInteger(); 181 final String authName = reader.readOctetStringAsString(); 182 final byte authType = reader.peekType(); 183 final byte[] authBytes = reader.readOctetString(authType).toByteArray(); 184 final GenericBindRequest request = 185 Requests.newGenericBindRequest(authName, authType, authBytes); 186 readControls(request); 187 logger.trace("DECODE LDAP BIND REQUEST(messageID=%d, auth=0x%x, request=%s)", 188 messageID, request.getAuthenticationType(), request); 189 190 handler.bindRequest(messageID, protocolVersion, request); 191 } finally { 192 reader.readEndSequence(); 193 } 194 } 195 196 private void readBindResult(final int messageID, final LDAPMessageHandler handler) 197 throws IOException { 198 reader.readStartSequence(LDAP.OP_TYPE_BIND_RESPONSE); 199 final BindResult message; 200 try { 201 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 202 final String matchedDN = reader.readOctetStringAsString(); 203 final String diagnosticMessage = reader.readOctetStringAsString(); 204 message = 205 Responses.newBindResult(resultCode).setMatchedDN(matchedDN) 206 .setDiagnosticMessage(diagnosticMessage); 207 readResponseReferrals(message); 208 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_SERVER_SASL_CREDENTIALS)) { 209 message.setServerSASLCredentials(reader 210 .readOctetString(LDAP.TYPE_SERVER_SASL_CREDENTIALS)); 211 } 212 } finally { 213 reader.readEndSequence(); 214 } 215 readControls(message); 216 logger.trace("DECODE LDAP BIND RESULT(messageID=%d, result=%s)", messageID, message); 217 handler.bindResult(messageID, message); 218 } 219 220 private void readCompareRequest(final int messageID, final LDAPMessageHandler handler) 221 throws IOException { 222 reader.readStartSequence(LDAP.OP_TYPE_COMPARE_REQUEST); 223 final CompareRequest message; 224 try { 225 final String dnString = reader.readOctetStringAsString(); 226 final Schema schema = options.getSchemaResolver().resolveSchema(dnString); 227 final DN dn = LDAP.readDN(dnString, schema); 228 reader.readStartSequence(); 229 try { 230 final String ads = reader.readOctetStringAsString(); 231 final AttributeDescription ad = LDAP.readAttributeDescription(ads, schema); 232 final ByteString assertionValue = reader.readOctetString(); 233 message = Requests.newCompareRequest(dn, ad, assertionValue); 234 } finally { 235 reader.readEndSequence(); 236 } 237 } finally { 238 reader.readEndSequence(); 239 } 240 readControls(message); 241 logger.trace("DECODE LDAP COMPARE REQUEST(messageID=%d, request=%s)", messageID, message); 242 handler.compareRequest(messageID, message); 243 } 244 245 private void readCompareResult(final int messageID, final LDAPMessageHandler handler) 246 throws IOException { 247 reader.readStartSequence(LDAP.OP_TYPE_COMPARE_RESPONSE); 248 final CompareResult message; 249 try { 250 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 251 final String matchedDN = reader.readOctetStringAsString(); 252 final String diagnosticMessage = reader.readOctetStringAsString(); 253 message = 254 Responses.newCompareResult(resultCode).setMatchedDN(matchedDN) 255 .setDiagnosticMessage(diagnosticMessage); 256 readResponseReferrals(message); 257 } finally { 258 reader.readEndSequence(); 259 } 260 readControls(message); 261 logger.trace("DECODE LDAP COMPARE RESULT(messageID=%d, result=%s)", messageID, message); 262 handler.compareResult(messageID, message); 263 } 264 265 private Control readControl() throws IOException { 266 reader.readStartSequence(); 267 try { 268 final String oid = reader.readOctetStringAsString(); 269 final boolean isCritical; 270 if (reader.hasNextElement() && (reader.peekType() == ASN1.UNIVERSAL_BOOLEAN_TYPE)) { 271 isCritical = reader.readBoolean(); 272 } else { 273 isCritical = false; 274 } 275 final ByteString value; 276 if (reader.hasNextElement() && (reader.peekType() == ASN1.UNIVERSAL_OCTET_STRING_TYPE)) { 277 value = reader.readOctetString(); 278 } else { 279 value = null; 280 } 281 return GenericControl.newControl(oid, isCritical, value); 282 } finally { 283 reader.readEndSequence(); 284 } 285 } 286 287 private void readControls(final Request request) throws IOException { 288 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_CONTROL_SEQUENCE)) { 289 reader.readStartSequence(LDAP.TYPE_CONTROL_SEQUENCE); 290 try { 291 while (reader.hasNextElement()) { 292 request.addControl(readControl()); 293 } 294 } finally { 295 reader.readEndSequence(); 296 } 297 } 298 } 299 300 private void readControls(final Response response) throws IOException { 301 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_CONTROL_SEQUENCE)) { 302 reader.readStartSequence(LDAP.TYPE_CONTROL_SEQUENCE); 303 try { 304 while (reader.hasNextElement()) { 305 response.addControl(readControl()); 306 } 307 } finally { 308 reader.readEndSequence(); 309 } 310 } 311 } 312 313 private void readDeleteRequest(final int messageID, final LDAPMessageHandler handler) 314 throws IOException { 315 final String dnString = reader.readOctetStringAsString(LDAP.OP_TYPE_DELETE_REQUEST); 316 final Schema schema = options.getSchemaResolver().resolveSchema(dnString); 317 final DN dn = LDAP.readDN(dnString, schema); 318 final DeleteRequest message = Requests.newDeleteRequest(dn); 319 readControls(message); 320 logger.trace("DECODE LDAP DELETE REQUEST(messageID=%d, request=%s)", messageID, message); 321 handler.deleteRequest(messageID, message); 322 } 323 324 private void readDeleteResult(final int messageID, final LDAPMessageHandler handler) 325 throws IOException { 326 reader.readStartSequence(LDAP.OP_TYPE_DELETE_RESPONSE); 327 final Result message; 328 try { 329 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 330 final String matchedDN = reader.readOctetStringAsString(); 331 final String diagnosticMessage = reader.readOctetStringAsString(); 332 message = 333 Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( 334 diagnosticMessage); 335 readResponseReferrals(message); 336 } finally { 337 reader.readEndSequence(); 338 } 339 readControls(message); 340 logger.trace("DECODE LDAP DELETE RESULT(messageID=%d, result=%s)", messageID, message); 341 handler.deleteResult(messageID, message); 342 } 343 344 private void readExtendedRequest(final int messageID, final LDAPMessageHandler handler) 345 throws IOException { 346 reader.readStartSequence(LDAP.OP_TYPE_EXTENDED_REQUEST); 347 final GenericExtendedRequest message; 348 try { 349 final String oid = reader.readOctetStringAsString(LDAP.TYPE_EXTENDED_REQUEST_OID); 350 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_EXTENDED_REQUEST_VALUE)) { 351 final ByteString value = reader.readOctetString(LDAP.TYPE_EXTENDED_REQUEST_VALUE); 352 message = Requests.newGenericExtendedRequest(oid, value); 353 } else { 354 message = Requests.newGenericExtendedRequest(oid, null); 355 } 356 } finally { 357 reader.readEndSequence(); 358 } 359 readControls(message); 360 logger.trace("DECODE LDAP EXTENDED REQUEST(messageID=%d, request=%s)", messageID, message); 361 handler.extendedRequest(messageID, message); 362 } 363 364 private void readExtendedResult(final int messageID, final LDAPMessageHandler handler) 365 throws IOException { 366 reader.readStartSequence(LDAP.OP_TYPE_EXTENDED_RESPONSE); 367 final GenericExtendedResult message; 368 try { 369 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 370 final String matchedDN = reader.readOctetStringAsString(); 371 final String diagnosticMessage = reader.readOctetStringAsString(); 372 message = 373 Responses.newGenericExtendedResult(resultCode).setMatchedDN(matchedDN) 374 .setDiagnosticMessage(diagnosticMessage); 375 readResponseReferrals(message); 376 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_EXTENDED_RESPONSE_OID)) { 377 message.setOID(reader.readOctetStringAsString(LDAP.TYPE_EXTENDED_RESPONSE_OID)); 378 } 379 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_EXTENDED_RESPONSE_VALUE)) { 380 message.setValue(reader.readOctetString(LDAP.TYPE_EXTENDED_RESPONSE_VALUE)); 381 } 382 } finally { 383 reader.readEndSequence(); 384 } 385 readControls(message); 386 logger.trace("DECODE LDAP EXTENDED RESULT(messageID=%d, result=%s)", messageID, message); 387 handler.extendedResult(messageID, message); 388 } 389 390 private void readIntermediateResponse(final int messageID, final LDAPMessageHandler handler) 391 throws IOException { 392 reader.readStartSequence(LDAP.OP_TYPE_INTERMEDIATE_RESPONSE); 393 final GenericIntermediateResponse message; 394 try { 395 message = Responses.newGenericIntermediateResponse(); 396 if (reader.hasNextElement() 397 && (reader.peekType() == LDAP.TYPE_INTERMEDIATE_RESPONSE_OID)) { 398 message.setOID(reader.readOctetStringAsString(LDAP.TYPE_INTERMEDIATE_RESPONSE_OID)); 399 } 400 if (reader.hasNextElement() 401 && (reader.peekType() == LDAP.TYPE_INTERMEDIATE_RESPONSE_VALUE)) { 402 message.setValue(reader.readOctetString(LDAP.TYPE_INTERMEDIATE_RESPONSE_VALUE)); 403 } 404 } finally { 405 reader.readEndSequence(); 406 } 407 readControls(message); 408 logger.trace("DECODE LDAP INTERMEDIATE RESPONSE(messageID=%d, response=%s)", messageID, message); 409 handler.intermediateResponse(messageID, message); 410 } 411 412 private void readModifyDNRequest(final int messageID, final LDAPMessageHandler handler) 413 throws IOException { 414 reader.readStartSequence(LDAP.OP_TYPE_MODIFY_DN_REQUEST); 415 final ModifyDNRequest message; 416 try { 417 final String dnString = reader.readOctetStringAsString(); 418 final Schema schema = options.getSchemaResolver().resolveSchema(dnString); 419 final DN dn = LDAP.readDN(dnString, schema); 420 final String newRDNString = reader.readOctetStringAsString(); 421 final RDN newRDN = readRDN(newRDNString, schema); 422 message = Requests.newModifyDNRequest(dn, newRDN); 423 message.setDeleteOldRDN(reader.readBoolean()); 424 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_MODIFY_DN_NEW_SUPERIOR)) { 425 final String newSuperiorString = 426 reader.readOctetStringAsString(LDAP.TYPE_MODIFY_DN_NEW_SUPERIOR); 427 final DN newSuperior = LDAP.readDN(newSuperiorString, schema); 428 message.setNewSuperior(newSuperior); 429 } 430 } finally { 431 reader.readEndSequence(); 432 } 433 readControls(message); 434 logger.trace("DECODE LDAP MODIFY DN REQUEST(messageID=%d, request=%s)", messageID, message); 435 handler.modifyDNRequest(messageID, message); 436 } 437 438 private void readModifyDNResult(final int messageID, final LDAPMessageHandler handler) 439 throws IOException { 440 reader.readStartSequence(LDAP.OP_TYPE_MODIFY_DN_RESPONSE); 441 final Result message; 442 try { 443 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 444 final String matchedDN = reader.readOctetStringAsString(); 445 final String diagnosticMessage = reader.readOctetStringAsString(); 446 message = 447 Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( 448 diagnosticMessage); 449 readResponseReferrals(message); 450 } finally { 451 reader.readEndSequence(); 452 } 453 readControls(message); 454 logger.trace("DECODE LDAP MODIFY DN RESULT(messageID=%d, result=%s)", messageID, message); 455 handler.modifyDNResult(messageID, message); 456 } 457 458 private void readModifyRequest(final int messageID, final LDAPMessageHandler handler) 459 throws IOException { 460 reader.readStartSequence(LDAP.OP_TYPE_MODIFY_REQUEST); 461 final ModifyRequest message; 462 try { 463 final String dnString = reader.readOctetStringAsString(); 464 final Schema schema = options.getSchemaResolver().resolveSchema(dnString); 465 final DN dn = LDAP.readDN(dnString, schema); 466 message = Requests.newModifyRequest(dn); 467 reader.readStartSequence(); 468 try { 469 while (reader.hasNextElement()) { 470 reader.readStartSequence(); 471 try { 472 final int typeIntValue = reader.readEnumerated(); 473 final ModificationType type = ModificationType.valueOf(typeIntValue); 474 if (type == null) { 475 throw DecodeException 476 .error(ERR_LDAP_MODIFICATION_DECODE_INVALID_MOD_TYPE 477 .get(typeIntValue)); 478 } 479 reader.readStartSequence(); 480 try { 481 final String ads = reader.readOctetStringAsString(); 482 final AttributeDescription ad = 483 LDAP.readAttributeDescription(ads, schema); 484 final Attribute attribute = 485 options.getAttributeFactory().newAttribute(ad); 486 reader.readStartSet(); 487 try { 488 while (reader.hasNextElement()) { 489 attribute.add(reader.readOctetString()); 490 } 491 message.addModification(new Modification(type, attribute)); 492 } finally { 493 reader.readEndSet(); 494 } 495 } finally { 496 reader.readEndSequence(); 497 } 498 } finally { 499 reader.readEndSequence(); 500 } 501 } 502 } finally { 503 reader.readEndSequence(); 504 } 505 } finally { 506 reader.readEndSequence(); 507 } 508 readControls(message); 509 logger.trace("DECODE LDAP MODIFY REQUEST(messageID=%d, request=%s)", messageID, message); 510 handler.modifyRequest(messageID, message); 511 } 512 513 private void readModifyResult(final int messageID, final LDAPMessageHandler handler) 514 throws IOException { 515 reader.readStartSequence(LDAP.OP_TYPE_MODIFY_RESPONSE); 516 final Result message; 517 try { 518 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 519 final String matchedDN = reader.readOctetStringAsString(); 520 final String diagnosticMessage = reader.readOctetStringAsString(); 521 message = 522 Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( 523 diagnosticMessage); 524 readResponseReferrals(message); 525 } finally { 526 reader.readEndSequence(); 527 } 528 readControls(message); 529 logger.trace("DECODE LDAP MODIFY RESULT(messageID=%d, result=%s)", messageID, message); 530 handler.modifyResult(messageID, message); 531 } 532 533 private void readProtocolOp(final int messageID, final LDAPMessageHandler handler) 534 throws IOException { 535 final byte type = reader.peekType(); 536 switch (type) { 537 case LDAP.OP_TYPE_UNBIND_REQUEST: // 0x42 538 readUnbindRequest(messageID, handler); 539 break; 540 case LDAP.OP_TYPE_DELETE_REQUEST: // 0x4A 541 readDeleteRequest(messageID, handler); 542 break; 543 case LDAP.OP_TYPE_ABANDON_REQUEST: // 0x50 544 readAbandonRequest(messageID, handler); 545 break; 546 case LDAP.OP_TYPE_BIND_REQUEST: // 0x60 547 readBindRequest(messageID, handler); 548 break; 549 case LDAP.OP_TYPE_BIND_RESPONSE: // 0x61 550 readBindResult(messageID, handler); 551 break; 552 case LDAP.OP_TYPE_SEARCH_REQUEST: // 0x63 553 readSearchRequest(messageID, handler); 554 break; 555 case LDAP.OP_TYPE_SEARCH_RESULT_ENTRY: // 0x64 556 readSearchResultEntry(messageID, handler); 557 break; 558 case LDAP.OP_TYPE_SEARCH_RESULT_DONE: // 0x65 559 readSearchResult(messageID, handler); 560 break; 561 case LDAP.OP_TYPE_MODIFY_REQUEST: // 0x66 562 readModifyRequest(messageID, handler); 563 break; 564 case LDAP.OP_TYPE_MODIFY_RESPONSE: // 0x67 565 readModifyResult(messageID, handler); 566 break; 567 case LDAP.OP_TYPE_ADD_REQUEST: // 0x68 568 readAddRequest(messageID, handler); 569 break; 570 case LDAP.OP_TYPE_ADD_RESPONSE: // 0x69 571 readAddResult(messageID, handler); 572 break; 573 case LDAP.OP_TYPE_DELETE_RESPONSE: // 0x6B 574 readDeleteResult(messageID, handler); 575 break; 576 case LDAP.OP_TYPE_MODIFY_DN_REQUEST: // 0x6C 577 readModifyDNRequest(messageID, handler); 578 break; 579 case LDAP.OP_TYPE_MODIFY_DN_RESPONSE: // 0x6D 580 readModifyDNResult(messageID, handler); 581 break; 582 case LDAP.OP_TYPE_COMPARE_REQUEST: // 0x6E 583 readCompareRequest(messageID, handler); 584 break; 585 case LDAP.OP_TYPE_COMPARE_RESPONSE: // 0x6F 586 readCompareResult(messageID, handler); 587 break; 588 case LDAP.OP_TYPE_SEARCH_RESULT_REFERENCE: // 0x73 589 readSearchResultReference(messageID, handler); 590 break; 591 case LDAP.OP_TYPE_EXTENDED_REQUEST: // 0x77 592 readExtendedRequest(messageID, handler); 593 break; 594 case LDAP.OP_TYPE_EXTENDED_RESPONSE: // 0x78 595 readExtendedResult(messageID, handler); 596 break; 597 case LDAP.OP_TYPE_INTERMEDIATE_RESPONSE: // 0x79 598 readIntermediateResponse(messageID, handler); 599 break; 600 default: 601 handler.unrecognizedMessage(messageID, type, reader.readOctetString(type)); 602 break; 603 } 604 } 605 606 private RDN readRDN(final String rdn, final Schema schema) throws DecodeException { 607 try { 608 return RDN.valueOf(rdn, schema); 609 } catch (final LocalizedIllegalArgumentException e) { 610 throw DecodeException.error(e.getMessageObject()); 611 } 612 } 613 614 private void readResponseReferrals(final Result message) throws IOException { 615 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_REFERRAL_SEQUENCE)) { 616 reader.readStartSequence(LDAP.TYPE_REFERRAL_SEQUENCE); 617 try { 618 // Should have at least 1. 619 do { 620 message.addReferralURI((reader.readOctetStringAsString())); 621 } while (reader.hasNextElement()); 622 } finally { 623 reader.readEndSequence(); 624 } 625 } 626 } 627 628 private void readSearchRequest(final int messageID, final LDAPMessageHandler handler) 629 throws IOException { 630 reader.readStartSequence(LDAP.OP_TYPE_SEARCH_REQUEST); 631 final SearchRequest message; 632 try { 633 final String baseDNString = reader.readOctetStringAsString(); 634 final Schema schema = options.getSchemaResolver().resolveSchema(baseDNString); 635 final DN baseDN = LDAP.readDN(baseDNString, schema); 636 final int scopeIntValue = reader.readEnumerated(); 637 final SearchScope scope = SearchScope.valueOf(scopeIntValue); 638 if (scope == null) { 639 throw DecodeException.error(ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_SCOPE 640 .get(scopeIntValue)); 641 } 642 final int dereferencePolicyIntValue = reader.readEnumerated(); 643 final DereferenceAliasesPolicy dereferencePolicy = 644 DereferenceAliasesPolicy.valueOf(dereferencePolicyIntValue); 645 if (dereferencePolicy == null) { 646 throw DecodeException.error(ERR_LDAP_SEARCH_REQUEST_DECODE_INVALID_DEREF 647 .get(dereferencePolicyIntValue)); 648 } 649 final int sizeLimit = (int) reader.readInteger(); 650 final int timeLimit = (int) reader.readInteger(); 651 final boolean typesOnly = reader.readBoolean(); 652 final Filter filter = LDAP.readFilter(reader); 653 message = Requests.newSearchRequest(baseDN, scope, filter); 654 message.setDereferenceAliasesPolicy(dereferencePolicy); 655 try { 656 message.setTimeLimit(timeLimit); 657 message.setSizeLimit(sizeLimit); 658 } catch (final LocalizedIllegalArgumentException e) { 659 throw DecodeException.error(e.getMessageObject()); 660 } 661 message.setTypesOnly(typesOnly); 662 reader.readStartSequence(); 663 try { 664 while (reader.hasNextElement()) { 665 message.addAttribute(reader.readOctetStringAsString()); 666 } 667 } finally { 668 reader.readEndSequence(); 669 } 670 } finally { 671 reader.readEndSequence(); 672 } 673 readControls(message); 674 logger.trace("DECODE LDAP SEARCH REQUEST(messageID=%d, request=%s)", messageID, message); 675 handler.searchRequest(messageID, message); 676 } 677 678 private void readSearchResult(final int messageID, final LDAPMessageHandler handler) 679 throws IOException { 680 reader.readStartSequence(LDAP.OP_TYPE_SEARCH_RESULT_DONE); 681 final Result message; 682 try { 683 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 684 final String matchedDN = reader.readOctetStringAsString(); 685 final String diagnosticMessage = reader.readOctetStringAsString(); 686 message = 687 Responses.newResult(resultCode).setMatchedDN(matchedDN).setDiagnosticMessage( 688 diagnosticMessage); 689 readResponseReferrals(message); 690 } finally { 691 reader.readEndSequence(); 692 } 693 readControls(message); 694 logger.trace("DECODE LDAP SEARCH RESULT(messageID=%d, result=%s)", messageID, message); 695 handler.searchResult(messageID, message); 696 } 697 698 private void readSearchResultEntry(final int messageID, final LDAPMessageHandler handler) 699 throws IOException { 700 final Entry entry = LDAP.readEntry(reader, LDAP.OP_TYPE_SEARCH_RESULT_ENTRY, options); 701 final SearchResultEntry message = Responses.newSearchResultEntry(entry); 702 readControls(message); 703 logger.trace("DECODE LDAP SEARCH RESULT ENTRY(messageID=%d, entry=%s)", messageID, message); 704 handler.searchResultEntry(messageID, message); 705 } 706 707 private void readSearchResultReference(final int messageID, final LDAPMessageHandler handler) 708 throws IOException { 709 reader.readStartSequence(LDAP.OP_TYPE_SEARCH_RESULT_REFERENCE); 710 final SearchResultReference message; 711 try { 712 message = Responses.newSearchResultReference(reader.readOctetStringAsString()); 713 while (reader.hasNextElement()) { 714 message.addURI(reader.readOctetStringAsString()); 715 } 716 } finally { 717 reader.readEndSequence(); 718 } 719 readControls(message); 720 logger.trace("DECODE LDAP SEARCH RESULT REFERENCE(messageID=%d, reference=%s)", messageID, message); 721 handler.searchResultReference(messageID, message); 722 } 723 724 private void readUnbindRequest(final int messageID, final LDAPMessageHandler handler) 725 throws IOException { 726 reader.readNull(LDAP.OP_TYPE_UNBIND_REQUEST); 727 final UnbindRequest message = Requests.newUnbindRequest(); 728 readControls(message); 729 logger.trace("DECODE LDAP UNBIND REQUEST(messageID=%d, request=%s)", messageID, message); 730 handler.unbindRequest(messageID, message); 731 } 732}