001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2013-2015 ForgeRock AS. 015 */ 016 017package org.forgerock.opendj.io; 018 019import java.io.IOException; 020import java.util.Collections; 021import java.util.LinkedList; 022import java.util.List; 023 024import org.forgerock.i18n.LocalizedIllegalArgumentException; 025import org.forgerock.opendj.ldap.Attribute; 026import org.forgerock.opendj.ldap.AttributeDescription; 027import org.forgerock.opendj.ldap.ByteSequence; 028import org.forgerock.opendj.ldap.ByteString; 029import org.forgerock.opendj.ldap.DN; 030import org.forgerock.opendj.ldap.DecodeException; 031import org.forgerock.opendj.ldap.DecodeOptions; 032import org.forgerock.opendj.ldap.Entry; 033import org.forgerock.opendj.ldap.Filter; 034import org.forgerock.opendj.ldap.FilterVisitor; 035import org.forgerock.opendj.ldap.schema.Schema; 036 037/** 038 * This class contains various static utility methods encoding and decoding LDAP 039 * protocol elements. 040 * 041 * @see LDAPReader 042 * @see LDAPWriter 043 */ 044public final class LDAP { 045 // @Checkstyle:ignore AvoidNestedBlocks 046 047 /** 048 * The OID for the Kerberos V GSSAPI mechanism. 049 */ 050 public static final String OID_GSSAPI_KERBEROS_V = "1.2.840.113554.1.2.2"; 051 052 /** 053 * The OID for the LDAP notice of disconnection extended operation. 054 */ 055 public static final String OID_NOTICE_OF_DISCONNECTION = "1.3.6.1.4.1.1466.20036"; 056 057 /** 058 * The protocol op type for abandon requests. 059 */ 060 public static final byte OP_TYPE_ABANDON_REQUEST = 0x50; 061 062 /** 063 * The protocol op type for add requests. 064 */ 065 public static final byte OP_TYPE_ADD_REQUEST = 0x68; 066 067 /** 068 * The protocol op type for add responses. 069 */ 070 public static final byte OP_TYPE_ADD_RESPONSE = 0x69; 071 072 /** 073 * The protocol op type for bind requests. 074 */ 075 public static final byte OP_TYPE_BIND_REQUEST = 0x60; 076 077 /** 078 * The protocol op type for bind responses. 079 */ 080 public static final byte OP_TYPE_BIND_RESPONSE = 0x61; 081 082 /** 083 * The protocol op type for compare requests. 084 */ 085 public static final byte OP_TYPE_COMPARE_REQUEST = 0x6E; 086 087 /** 088 * The protocol op type for compare responses. 089 */ 090 public static final byte OP_TYPE_COMPARE_RESPONSE = 0x6F; 091 092 /** 093 * The protocol op type for delete requests. 094 */ 095 public static final byte OP_TYPE_DELETE_REQUEST = 0x4A; 096 097 /** 098 * The protocol op type for delete responses. 099 */ 100 public static final byte OP_TYPE_DELETE_RESPONSE = 0x6B; 101 102 /** 103 * The protocol op type for extended requests. 104 */ 105 public static final byte OP_TYPE_EXTENDED_REQUEST = 0x77; 106 107 /** 108 * The protocol op type for extended responses. 109 */ 110 public static final byte OP_TYPE_EXTENDED_RESPONSE = 0x78; 111 112 /** 113 * The protocol op type for intermediate responses. 114 */ 115 public static final byte OP_TYPE_INTERMEDIATE_RESPONSE = 0x79; 116 117 /** 118 * The protocol op type for modify DN requests. 119 */ 120 public static final byte OP_TYPE_MODIFY_DN_REQUEST = 0x6C; 121 122 /** 123 * The protocol op type for modify DN responses. 124 */ 125 public static final byte OP_TYPE_MODIFY_DN_RESPONSE = 0x6D; 126 127 /** 128 * The protocol op type for modify requests. 129 */ 130 public static final byte OP_TYPE_MODIFY_REQUEST = 0x66; 131 132 /** 133 * The protocol op type for modify responses. 134 */ 135 public static final byte OP_TYPE_MODIFY_RESPONSE = 0x67; 136 /** 137 * The protocol op type for search requests. 138 */ 139 public static final byte OP_TYPE_SEARCH_REQUEST = 0x63; 140 /** 141 * The protocol op type for search result done elements. 142 */ 143 public static final byte OP_TYPE_SEARCH_RESULT_DONE = 0x65; 144 /** 145 * The protocol op type for search result entries. 146 */ 147 public static final byte OP_TYPE_SEARCH_RESULT_ENTRY = 0x64; 148 /** 149 * The protocol op type for search result references. 150 */ 151 public static final byte OP_TYPE_SEARCH_RESULT_REFERENCE = 0x73; 152 /** 153 * The protocol op type for unbind requests. 154 */ 155 public static final byte OP_TYPE_UNBIND_REQUEST = 0x42; 156 /** 157 * The BER type to use for the AuthenticationChoice element in a bind 158 * request when SASL authentication is to be used. 159 */ 160 public static final byte TYPE_AUTHENTICATION_SASL = (byte) 0xA3; 161 /** 162 * The BER type to use for the AuthenticationChoice element in a bind 163 * request when simple authentication is to be used. 164 */ 165 public static final byte TYPE_AUTHENTICATION_SIMPLE = (byte) 0x80; 166 /** 167 * The BER type to use for encoding the sequence of controls in an LDAP 168 * message. 169 */ 170 public static final byte TYPE_CONTROL_SEQUENCE = (byte) 0xA0; 171 /** 172 * The BER type to use for the OID of an extended request. 173 */ 174 public static final byte TYPE_EXTENDED_REQUEST_OID = (byte) 0x80; 175 /** 176 * The BER type to use for the value of an extended request. 177 */ 178 public static final byte TYPE_EXTENDED_REQUEST_VALUE = (byte) 0x81; 179 /** 180 * The BER type to use for the OID of an extended response. 181 */ 182 public static final byte TYPE_EXTENDED_RESPONSE_OID = (byte) 0x8A; 183 /** 184 * The BER type to use for the value of an extended response. 185 */ 186 public static final byte TYPE_EXTENDED_RESPONSE_VALUE = (byte) 0x8B; 187 /** 188 * The BER type to use for AND filter components. 189 */ 190 public static final byte TYPE_FILTER_AND = (byte) 0xA0; 191 /** 192 * The BER type to use for approximate filter components. 193 */ 194 public static final byte TYPE_FILTER_APPROXIMATE = (byte) 0xA8; 195 /** 196 * The BER type to use for equality filter components. 197 */ 198 public static final byte TYPE_FILTER_EQUALITY = (byte) 0xA3; 199 /** 200 * The BER type to use for extensible matching filter components. 201 */ 202 public static final byte TYPE_FILTER_EXTENSIBLE_MATCH = (byte) 0xA9; 203 /** 204 * The BER type to use for greater than or equal to filter components. 205 */ 206 public static final byte TYPE_FILTER_GREATER_OR_EQUAL = (byte) 0xA5; 207 /** 208 * The BER type to use for less than or equal to filter components. 209 */ 210 public static final byte TYPE_FILTER_LESS_OR_EQUAL = (byte) 0xA6; 211 /** 212 * The BER type to use for NOT filter components. 213 */ 214 public static final byte TYPE_FILTER_NOT = (byte) 0xA2; 215 /** 216 * The BER type to use for OR filter components. 217 */ 218 public static final byte TYPE_FILTER_OR = (byte) 0xA1; 219 /** 220 * The BER type to use for presence filter components. 221 */ 222 public static final byte TYPE_FILTER_PRESENCE = (byte) 0x87; 223 /** 224 * The BER type to use for substring filter components. 225 */ 226 public static final byte TYPE_FILTER_SUBSTRING = (byte) 0xA4; 227 /** 228 * The BER type to use for the OID of an intermediate response message. 229 */ 230 public static final byte TYPE_INTERMEDIATE_RESPONSE_OID = (byte) 0x80; 231 /** 232 * The BER type to use for the value of an intermediate response message. 233 */ 234 public static final byte TYPE_INTERMEDIATE_RESPONSE_VALUE = (byte) 0x81; 235 /** 236 * The BER type to use for the DN attributes flag in a matching rule 237 * assertion. 238 */ 239 public static final byte TYPE_MATCHING_RULE_DN_ATTRIBUTES = (byte) 0x84; 240 /** 241 * The BER type to use for the matching rule OID in a matching rule 242 * assertion. 243 */ 244 public static final byte TYPE_MATCHING_RULE_ID = (byte) 0x81; 245 /** 246 * The BER type to use for the attribute type in a matching rule assertion. 247 */ 248 public static final byte TYPE_MATCHING_RULE_TYPE = (byte) 0x82; 249 /** 250 * The BER type to use for the assertion value in a matching rule assertion. 251 */ 252 public static final byte TYPE_MATCHING_RULE_VALUE = (byte) 0x83; 253 /** 254 * The BER type to use for the newSuperior component of a modify DN request. 255 */ 256 public static final byte TYPE_MODIFY_DN_NEW_SUPERIOR = (byte) 0x80; 257 /** 258 * The BER type to use for encoding the sequence of referral URLs in an 259 * LDAPResult element. 260 */ 261 public static final byte TYPE_REFERRAL_SEQUENCE = (byte) 0xA3; 262 /** 263 * The BER type to use for the server SASL credentials in a bind response. 264 */ 265 public static final byte TYPE_SERVER_SASL_CREDENTIALS = (byte) 0x87; 266 /** 267 * The BER type to use for the subAny component(s) of a substring filter. 268 */ 269 public static final byte TYPE_SUBANY = (byte) 0x81; 270 /** 271 * The BER type to use for the subFinal components of a substring filter. 272 */ 273 public static final byte TYPE_SUBFINAL = (byte) 0x82; 274 /** 275 * The BER type to use for the subInitial component of a substring filter. 276 */ 277 public static final byte TYPE_SUBINITIAL = (byte) 0x80; 278 private static final FilterVisitor<IOException, ASN1Writer> ASN1_ENCODER = 279 new FilterVisitor<IOException, ASN1Writer>() { 280 281 @Override 282 public IOException visitAndFilter(final ASN1Writer writer, 283 final List<Filter> subFilters) { 284 try { 285 writer.writeStartSequence(LDAP.TYPE_FILTER_AND); 286 for (final Filter subFilter : subFilters) { 287 final IOException e = subFilter.accept(this, writer); 288 if (e != null) { 289 return e; 290 } 291 } 292 writer.writeEndSequence(); 293 return null; 294 } catch (final IOException e) { 295 return e; 296 } 297 } 298 299 @Override 300 public IOException visitApproxMatchFilter(final ASN1Writer writer, 301 final String attributeDescription, final ByteString assertionValue) { 302 try { 303 writer.writeStartSequence(LDAP.TYPE_FILTER_APPROXIMATE); 304 writer.writeOctetString(attributeDescription); 305 writer.writeOctetString(assertionValue); 306 writer.writeEndSequence(); 307 return null; 308 } catch (final IOException e) { 309 return e; 310 } 311 } 312 313 @Override 314 public IOException visitEqualityMatchFilter(final ASN1Writer writer, 315 final String attributeDescription, final ByteString assertionValue) { 316 try { 317 writer.writeStartSequence(LDAP.TYPE_FILTER_EQUALITY); 318 writer.writeOctetString(attributeDescription); 319 writer.writeOctetString(assertionValue); 320 writer.writeEndSequence(); 321 return null; 322 } catch (final IOException e) { 323 return e; 324 } 325 } 326 327 @Override 328 public IOException visitExtensibleMatchFilter(final ASN1Writer writer, 329 final String matchingRule, final String attributeDescription, 330 final ByteString assertionValue, final boolean dnAttributes) { 331 try { 332 writer.writeStartSequence(LDAP.TYPE_FILTER_EXTENSIBLE_MATCH); 333 334 if (matchingRule != null) { 335 writer.writeOctetString(LDAP.TYPE_MATCHING_RULE_ID, matchingRule); 336 } 337 338 if (attributeDescription != null) { 339 writer.writeOctetString(LDAP.TYPE_MATCHING_RULE_TYPE, 340 attributeDescription); 341 } 342 343 writer.writeOctetString(LDAP.TYPE_MATCHING_RULE_VALUE, assertionValue); 344 345 if (dnAttributes) { 346 writer.writeBoolean(LDAP.TYPE_MATCHING_RULE_DN_ATTRIBUTES, true); 347 } 348 349 writer.writeEndSequence(); 350 return null; 351 } catch (final IOException e) { 352 return e; 353 } 354 } 355 356 @Override 357 public IOException visitGreaterOrEqualFilter(final ASN1Writer writer, 358 final String attributeDescription, final ByteString assertionValue) { 359 try { 360 writer.writeStartSequence(LDAP.TYPE_FILTER_GREATER_OR_EQUAL); 361 writer.writeOctetString(attributeDescription); 362 writer.writeOctetString(assertionValue); 363 writer.writeEndSequence(); 364 return null; 365 } catch (final IOException e) { 366 return e; 367 } 368 } 369 370 @Override 371 public IOException visitLessOrEqualFilter(final ASN1Writer writer, 372 final String attributeDescription, final ByteString assertionValue) { 373 try { 374 writer.writeStartSequence(LDAP.TYPE_FILTER_LESS_OR_EQUAL); 375 writer.writeOctetString(attributeDescription); 376 writer.writeOctetString(assertionValue); 377 writer.writeEndSequence(); 378 return null; 379 } catch (final IOException e) { 380 return e; 381 } 382 } 383 384 @Override 385 public IOException visitNotFilter(final ASN1Writer writer, final Filter subFilter) { 386 try { 387 writer.writeStartSequence(LDAP.TYPE_FILTER_NOT); 388 final IOException e = subFilter.accept(this, writer); 389 if (e != null) { 390 return e; 391 } 392 writer.writeEndSequence(); 393 return null; 394 } catch (final IOException e) { 395 return e; 396 } 397 } 398 399 @Override 400 public IOException visitOrFilter(final ASN1Writer writer, 401 final List<Filter> subFilters) { 402 try { 403 writer.writeStartSequence(LDAP.TYPE_FILTER_OR); 404 for (final Filter subFilter : subFilters) { 405 final IOException e = subFilter.accept(this, writer); 406 if (e != null) { 407 return e; 408 } 409 } 410 writer.writeEndSequence(); 411 return null; 412 } catch (final IOException e) { 413 return e; 414 } 415 } 416 417 @Override 418 public IOException visitPresentFilter(final ASN1Writer writer, 419 final String attributeDescription) { 420 try { 421 writer.writeOctetString(LDAP.TYPE_FILTER_PRESENCE, attributeDescription); 422 return null; 423 } catch (final IOException e) { 424 return e; 425 } 426 } 427 428 @Override 429 public IOException visitSubstringsFilter(final ASN1Writer writer, 430 final String attributeDescription, final ByteString initialSubstring, 431 final List<ByteString> anySubstrings, final ByteString finalSubstring) { 432 try { 433 writer.writeStartSequence(LDAP.TYPE_FILTER_SUBSTRING); 434 writer.writeOctetString(attributeDescription); 435 436 writer.writeStartSequence(); 437 if (initialSubstring != null) { 438 writer.writeOctetString(LDAP.TYPE_SUBINITIAL, initialSubstring); 439 } 440 441 for (final ByteSequence anySubstring : anySubstrings) { 442 writer.writeOctetString(LDAP.TYPE_SUBANY, anySubstring); 443 } 444 445 if (finalSubstring != null) { 446 writer.writeOctetString(LDAP.TYPE_SUBFINAL, finalSubstring); 447 } 448 writer.writeEndSequence(); 449 450 writer.writeEndSequence(); 451 return null; 452 } catch (final IOException e) { 453 return e; 454 } 455 } 456 457 @Override 458 public IOException visitUnrecognizedFilter(final ASN1Writer writer, 459 final byte filterTag, final ByteString filterBytes) { 460 try { 461 writer.writeOctetString(filterTag, filterBytes); 462 return null; 463 } catch (final IOException e) { 464 return e; 465 } 466 } 467 }; 468 469 /** 470 * Creates a new LDAP reader which will read LDAP messages from an ASN.1 471 * reader using the provided decoding options. 472 * 473 * @param <R> 474 * The type of ASN.1 reader used for decoding elements. 475 * @param asn1Reader 476 * The ASN.1 reader from which LDAP messages will be read. 477 * @param options 478 * LDAP message decoding options. 479 * @return A new LDAP reader which will read LDAP messages from an ASN.1 480 * reader using the provided decoding options. 481 */ 482 public static <R extends ASN1Reader> LDAPReader<R> getReader(final R asn1Reader, 483 final DecodeOptions options) { 484 return new LDAPReader<>(asn1Reader, options); 485 } 486 487 /** 488 * Creates a new LDAP writer which will write LDAP messages to the provided 489 * ASN.1 writer. 490 * 491 * @param <W> 492 * The type of ASN.1 writer used for encoding elements. 493 * @param asn1Writer 494 * The ASN.1 writer to which LDAP messages will be written. 495 * @return A new LDAP writer which will write LDAP messages to the provided 496 * ASN.1 writer. 497 */ 498 public static <W extends ASN1Writer> LDAPWriter<W> getWriter(final W asn1Writer) { 499 return new LDAPWriter<>(asn1Writer); 500 } 501 502 /** 503 * Reads the next ASN.1 element from the provided {@code ASN1Reader} as a 504 * {@code Filter}. 505 * 506 * @param reader 507 * The {@code ASN1Reader} from which the ASN.1 encoded 508 * {@code Filter} should be read. 509 * @return The decoded {@code Filter}. 510 * @throws IOException 511 * If an error occurs while reading from {@code reader}. 512 */ 513 public static Filter readFilter(final ASN1Reader reader) throws IOException { 514 final byte type = reader.peekType(); 515 switch (type) { 516 case LDAP.TYPE_FILTER_AND: 517 return readAndFilter(reader); 518 case LDAP.TYPE_FILTER_OR: 519 return readOrFilter(reader); 520 case LDAP.TYPE_FILTER_NOT: 521 return readNotFilter(reader); 522 case LDAP.TYPE_FILTER_EQUALITY: 523 return readEqualityMatchFilter(reader); 524 case LDAP.TYPE_FILTER_GREATER_OR_EQUAL: 525 return readGreaterOrEqualMatchFilter(reader); 526 case LDAP.TYPE_FILTER_LESS_OR_EQUAL: 527 return readLessOrEqualMatchFilter(reader); 528 case LDAP.TYPE_FILTER_APPROXIMATE: 529 return readApproxMatchFilter(reader); 530 case LDAP.TYPE_FILTER_SUBSTRING: 531 return readSubstringsFilter(reader); 532 case LDAP.TYPE_FILTER_PRESENCE: 533 return Filter.present(reader.readOctetStringAsString(type)); 534 case LDAP.TYPE_FILTER_EXTENSIBLE_MATCH: 535 return readExtensibleMatchFilter(reader); 536 default: 537 return Filter.unrecognized(type, reader.readOctetString(type)); 538 } 539 } 540 541 /** 542 * Reads the next ASN.1 element from the provided {@code ASN1Reader} as a an 543 * {@code Entry}. 544 * 545 * @param reader 546 * The {@code ASN1Reader} from which the ASN.1 encoded 547 * {@code Entry} should be read. 548 * @param options 549 * The decode options to use when decoding the entry. 550 * @return The decoded {@code Entry}. 551 * @throws IOException 552 * If an error occurs while reading from {@code reader}. 553 */ 554 public static Entry readEntry(final ASN1Reader reader, final DecodeOptions options) 555 throws IOException { 556 return readEntry(reader, OP_TYPE_SEARCH_RESULT_ENTRY, options); 557 } 558 559 /** 560 * Writes a {@code Filter} to the provided {@code ASN1Writer}. 561 * 562 * @param writer 563 * The {@code ASN1Writer} to which the ASN.1 encoded 564 * {@code Filter} should be written. 565 * @param filter 566 * The filter. 567 * @throws IOException 568 * If an error occurs while writing to {@code writer}. 569 */ 570 public static void writeFilter(final ASN1Writer writer, final Filter filter) throws IOException { 571 final IOException e = filter.accept(ASN1_ENCODER, writer); 572 if (e != null) { 573 throw e; 574 } 575 } 576 577 /** 578 * Writes an {@code Entry} to the provided {@code ASN1Writer}. 579 * 580 * @param writer 581 * The {@code ASN1Writer} to which the ASN.1 encoded 582 * {@code Entry} should be written. 583 * @param entry 584 * The entry. 585 * @throws IOException 586 * If an error occurs while writing to {@code writer}. 587 */ 588 public static void writeEntry(final ASN1Writer writer, final Entry entry) throws IOException { 589 writeEntry(writer, OP_TYPE_SEARCH_RESULT_ENTRY, entry); 590 } 591 592 static AttributeDescription readAttributeDescription(final String attributeDescription, 593 final Schema schema) throws DecodeException { 594 try { 595 return AttributeDescription.valueOf(attributeDescription, schema); 596 } catch (final LocalizedIllegalArgumentException e) { 597 throw DecodeException.error(e.getMessageObject()); 598 } 599 } 600 601 static DN readDN(final String dn, final Schema schema) throws DecodeException { 602 try { 603 return DN.valueOf(dn, schema); 604 } catch (final LocalizedIllegalArgumentException e) { 605 throw DecodeException.error(e.getMessageObject()); 606 } 607 } 608 609 static Entry readEntry(final ASN1Reader reader, final byte tagType, final DecodeOptions options) 610 throws DecodeException, IOException { 611 reader.readStartSequence(tagType); 612 final Entry entry; 613 try { 614 final String dnString = reader.readOctetStringAsString(); 615 final Schema schema = options.getSchemaResolver().resolveSchema(dnString); 616 final DN dn = readDN(dnString, schema); 617 entry = options.getEntryFactory().newEntry(dn); 618 reader.readStartSequence(); 619 try { 620 while (reader.hasNextElement()) { 621 reader.readStartSequence(); 622 try { 623 final String ads = reader.readOctetStringAsString(); 624 final AttributeDescription ad = readAttributeDescription(ads, schema); 625 final Attribute attribute = options.getAttributeFactory().newAttribute(ad); 626 reader.readStartSet(); 627 try { 628 while (reader.hasNextElement()) { 629 attribute.add(reader.readOctetString()); 630 } 631 entry.addAttribute(attribute); 632 } finally { 633 reader.readEndSet(); 634 } 635 } finally { 636 reader.readEndSequence(); 637 } 638 } 639 } finally { 640 reader.readEndSequence(); 641 } 642 } finally { 643 reader.readEndSequence(); 644 } 645 return entry; 646 } 647 648 static void writeAttribute(final ASN1Writer writer, final Attribute attribute) 649 throws IOException { 650 writer.writeStartSequence(); 651 { 652 writer.writeOctetString(attribute.getAttributeDescriptionAsString()); 653 writer.writeStartSet(); 654 { 655 for (final ByteString value : attribute) { 656 writer.writeOctetString(value); 657 } 658 } 659 writer.writeEndSet(); 660 } 661 writer.writeEndSequence(); 662 } 663 664 static void writeEntry(final ASN1Writer writer, final byte typeTag, final Entry entry) 665 throws IOException { 666 writer.writeStartSequence(typeTag); 667 { 668 writer.writeOctetString(entry.getName().toString()); 669 writer.writeStartSequence(); 670 { 671 for (final Attribute attr : entry.getAllAttributes()) { 672 writeAttribute(writer, attr); 673 } 674 } 675 writer.writeEndSequence(); 676 } 677 writer.writeEndSequence(); 678 } 679 680 private static Filter readAndFilter(final ASN1Reader reader) throws IOException { 681 reader.readStartSequence(LDAP.TYPE_FILTER_AND); 682 try { 683 if (reader.hasNextElement()) { 684 final List<Filter> subFilters = new LinkedList<>(); 685 do { 686 subFilters.add(readFilter(reader)); 687 } while (reader.hasNextElement()); 688 return Filter.and(subFilters); 689 } else { 690 // No sub-filters - this is an RFC 4526 absolute true filter. 691 return Filter.alwaysTrue(); 692 } 693 } finally { 694 reader.readEndSequence(); 695 } 696 } 697 698 private static Filter readApproxMatchFilter(final ASN1Reader reader) throws IOException { 699 reader.readStartSequence(LDAP.TYPE_FILTER_APPROXIMATE); 700 try { 701 final String attributeDescription = reader.readOctetStringAsString(); 702 final ByteString assertionValue = reader.readOctetString(); 703 return Filter.approx(attributeDescription, assertionValue); 704 } finally { 705 reader.readEndSequence(); 706 } 707 708 } 709 710 private static Filter readEqualityMatchFilter(final ASN1Reader reader) throws IOException { 711 reader.readStartSequence(LDAP.TYPE_FILTER_EQUALITY); 712 try { 713 final String attributeDescription = reader.readOctetStringAsString(); 714 final ByteString assertionValue = reader.readOctetString(); 715 return Filter.equality(attributeDescription, assertionValue); 716 } finally { 717 reader.readEndSequence(); 718 } 719 } 720 721 private static Filter readExtensibleMatchFilter(final ASN1Reader reader) throws IOException { 722 reader.readStartSequence(LDAP.TYPE_FILTER_EXTENSIBLE_MATCH); 723 try { 724 String matchingRule = null; 725 if (reader.peekType() == LDAP.TYPE_MATCHING_RULE_ID) { 726 matchingRule = reader.readOctetStringAsString(LDAP.TYPE_MATCHING_RULE_ID); 727 } 728 String attributeDescription = null; 729 if (reader.peekType() == LDAP.TYPE_MATCHING_RULE_TYPE) { 730 attributeDescription = reader.readOctetStringAsString(LDAP.TYPE_MATCHING_RULE_TYPE); 731 } 732 boolean dnAttributes = false; 733 if (reader.hasNextElement() 734 && (reader.peekType() == LDAP.TYPE_MATCHING_RULE_DN_ATTRIBUTES)) { 735 dnAttributes = reader.readBoolean(); 736 } 737 final ByteString assertionValue = reader.readOctetString(LDAP.TYPE_MATCHING_RULE_VALUE); 738 return Filter.extensible(matchingRule, attributeDescription, assertionValue, 739 dnAttributes); 740 } finally { 741 reader.readEndSequence(); 742 } 743 } 744 745 private static Filter readGreaterOrEqualMatchFilter(final ASN1Reader reader) throws IOException { 746 reader.readStartSequence(LDAP.TYPE_FILTER_GREATER_OR_EQUAL); 747 try { 748 final String attributeDescription = reader.readOctetStringAsString(); 749 final ByteString assertionValue = reader.readOctetString(); 750 return Filter.greaterOrEqual(attributeDescription, assertionValue); 751 } finally { 752 reader.readEndSequence(); 753 } 754 } 755 756 private static Filter readLessOrEqualMatchFilter(final ASN1Reader reader) throws IOException { 757 reader.readStartSequence(LDAP.TYPE_FILTER_LESS_OR_EQUAL); 758 try { 759 final String attributeDescription = reader.readOctetStringAsString(); 760 final ByteString assertionValue = reader.readOctetString(); 761 return Filter.lessOrEqual(attributeDescription, assertionValue); 762 } finally { 763 reader.readEndSequence(); 764 } 765 } 766 767 private static Filter readNotFilter(final ASN1Reader reader) throws IOException { 768 reader.readStartSequence(LDAP.TYPE_FILTER_NOT); 769 try { 770 return Filter.not(readFilter(reader)); 771 } finally { 772 reader.readEndSequence(); 773 } 774 } 775 776 private static Filter readOrFilter(final ASN1Reader reader) throws IOException { 777 reader.readStartSequence(LDAP.TYPE_FILTER_OR); 778 try { 779 if (reader.hasNextElement()) { 780 final List<Filter> subFilters = new LinkedList<>(); 781 do { 782 subFilters.add(readFilter(reader)); 783 } while (reader.hasNextElement()); 784 return Filter.or(subFilters); 785 } else { 786 // No sub-filters - this is an RFC 4526 absolute false filter. 787 return Filter.alwaysFalse(); 788 } 789 } finally { 790 reader.readEndSequence(); 791 } 792 } 793 794 private static Filter readSubstringsFilter(final ASN1Reader reader) throws IOException { 795 reader.readStartSequence(LDAP.TYPE_FILTER_SUBSTRING); 796 try { 797 final String attributeDescription = reader.readOctetStringAsString(); 798 reader.readStartSequence(); 799 try { 800 // FIXME: There should be at least one element in this substring 801 // filter sequence. 802 ByteString initialSubstring = null; 803 if (reader.peekType() == LDAP.TYPE_SUBINITIAL) { 804 initialSubstring = reader.readOctetString(LDAP.TYPE_SUBINITIAL); 805 } 806 final List<ByteString> anySubstrings; 807 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_SUBANY)) { 808 anySubstrings = new LinkedList<>(); 809 do { 810 anySubstrings.add(reader.readOctetString(LDAP.TYPE_SUBANY)); 811 } while (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_SUBANY)); 812 } else { 813 anySubstrings = Collections.emptyList(); 814 } 815 ByteString finalSubstring = null; 816 if (reader.hasNextElement() && (reader.peekType() == LDAP.TYPE_SUBFINAL)) { 817 finalSubstring = reader.readOctetString(LDAP.TYPE_SUBFINAL); 818 } 819 return Filter.substrings(attributeDescription, initialSubstring, anySubstrings, 820 finalSubstring); 821 } finally { 822 reader.readEndSequence(); 823 } 824 } finally { 825 reader.readEndSequence(); 826 } 827 } 828 829 /** Prevent instantiation. */ 830 private LDAP() { 831 // Nothing to do. 832 } 833}