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