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 2006-2009 Sun Microsystems, Inc. 025 * Portions Copyright 2013-2015 ForgeRock AS 026 */ 027package org.opends.server.types; 028 029import org.forgerock.opendj.ldap.ByteString; 030import org.forgerock.i18n.LocalizableMessage; 031 032 033 034import java.util.ArrayList; 035import java.io.IOException; 036 037import org.forgerock.i18n.slf4j.LocalizedLogger; 038import org.forgerock.opendj.io.*; 039import org.opends.server.protocols.ldap.LDAPFilter; 040 041import static org.opends.messages.ProtocolMessages.*; 042import static org.opends.server.protocols.ldap.LDAPConstants.*; 043import static org.opends.server.protocols.ldap.LDAPResultCode.*; 044import static org.opends.server.util.StaticUtils.*; 045 046 047 048/** 049 * This class defines the data structures and methods to use when 050 * interacting with a raw search filter, which defines a set of 051 * criteria for locating entries in a search request. 052 */ 053@org.opends.server.types.PublicAPI( 054 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, 055 mayInstantiate=true, 056 mayExtend=false, 057 mayInvoke=true) 058public abstract class RawFilter 059{ 060 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 061 062 /** 063 * Creates a new LDAP filter from the provided filter string. 064 * 065 * @param filterString The filter string to use to create this raw 066 * filter. 067 * 068 * @return The raw filter decoded from the provided filter string. 069 * 070 * @throws LDAPException If the provied filter string could not be 071 * decoded as a raw filter. 072 */ 073 public static RawFilter create(String filterString) 074 throws LDAPException 075 { 076 return LDAPFilter.decode(filterString); 077 } 078 079 080 081 /** 082 * Creates a new LDAP filter from the provided search filter. 083 * 084 * @param filter The search filter to use to create this raw 085 * filter. 086 * 087 * @return The constructed raw filter. 088 */ 089 public static RawFilter create(SearchFilter filter) 090 { 091 return new LDAPFilter(filter); 092 } 093 094 095 096 /** 097 * Creates a new AND search filter with the provided filter 098 * components. 099 * 100 * @param filterComponents The filter components for this AND 101 * filter. 102 * 103 * @return The AND search filter with the provided filter 104 * components. 105 */ 106 public static LDAPFilter createANDFilter(ArrayList<RawFilter> 107 filterComponents) 108 { 109 return new LDAPFilter(FilterType.AND, filterComponents, null, 110 null, null, null, null, null, null, false); 111 } 112 113 114 115 /** 116 * Creates a new OR search filter with the provided filter 117 * components. 118 * 119 * @param filterComponents The filter components for this OR 120 * filter. 121 * 122 * @return The OR search filter with the provided filter 123 * components. 124 */ 125 public static LDAPFilter createORFilter(ArrayList<RawFilter> 126 filterComponents) 127 { 128 return new LDAPFilter(FilterType.OR, filterComponents, null, null, 129 null, null, null, null, null, false); 130 } 131 132 133 134 /** 135 * Creates a new NOT search filter with the provided filter 136 * component. 137 * 138 * @param notComponent The filter component for this NOT filter. 139 * 140 * @return The NOT search filter with the provided filter 141 * component. 142 */ 143 public static LDAPFilter createNOTFilter(RawFilter notComponent) 144 { 145 return new LDAPFilter(FilterType.NOT, null, notComponent, null, 146 null, null, null, null, null, false); 147 } 148 149 150 151 /** 152 * Creates a new equality search filter with the provided 153 * information. 154 * 155 * @param attributeType The attribute type for this equality 156 * filter. 157 * @param assertionValue The assertion value for this equality 158 * filter. 159 * 160 * @return The constructed equality search filter. 161 */ 162 public static LDAPFilter createEqualityFilter(String attributeType, 163 ByteString assertionValue) 164 { 165 return new LDAPFilter(FilterType.EQUALITY, null, null, 166 attributeType, assertionValue, null, null, 167 null, null, false); 168 } 169 170 171 172 /** 173 * Creates a new substring search filter with the provided 174 * information. 175 * 176 * @param attributeType The attribute type for this substring 177 * filter. 178 * @param subInitialElement The subInitial element for this 179 * substring filter. 180 * @param subAnyElements The subAny elements for this substring 181 * filter. 182 * @param subFinalElement The subFinal element for this 183 * substring filter. 184 * 185 * @return The constructed substring search filter. 186 */ 187 public static LDAPFilter createSubstringFilter(String attributeType, 188 ByteString subInitialElement, 189 ArrayList<ByteString> subAnyElements, 190 ByteString subFinalElement) 191 { 192 return new LDAPFilter(FilterType.SUBSTRING, null, null, 193 attributeType, null, subInitialElement, 194 subAnyElements, subFinalElement, null, 195 false); 196 } 197 198 199 200 /** 201 * Creates a new greater or equal search filter with the provided 202 * information. 203 * 204 * @param attributeType The attribute type for this greater or 205 * equal filter. 206 * @param assertionValue The assertion value for this greater or 207 * equal filter. 208 * 209 * @return The constructed greater or equal search filter. 210 */ 211 public static LDAPFilter createGreaterOrEqualFilter( 212 String attributeType, 213 ByteString assertionValue) 214 { 215 return new LDAPFilter(FilterType.GREATER_OR_EQUAL, null, null, 216 attributeType, assertionValue, null, null, 217 null, null, false); 218 } 219 220 221 222 /** 223 * Creates a new less or equal search filter with the provided 224 * information. 225 * 226 * @param attributeType The attribute type for this less or equal 227 * filter. 228 * @param assertionValue The assertion value for this less or 229 * equal filter. 230 * 231 * @return The constructed less or equal search filter. 232 */ 233 public static LDAPFilter createLessOrEqualFilter( 234 String attributeType, 235 ByteString assertionValue) 236 { 237 return new LDAPFilter(FilterType.LESS_OR_EQUAL, null, null, 238 attributeType, assertionValue, null, null, 239 null, null, false); 240 } 241 242 243 244 /** 245 * Creates a new presence search filter with the provided attribute 246 * type. 247 * 248 * @param attributeType The attribute type for this presence 249 * filter. 250 * 251 * @return The constructed presence search filter. 252 */ 253 public static LDAPFilter createPresenceFilter(String attributeType) 254 { 255 return new LDAPFilter(FilterType.PRESENT, null, null, 256 attributeType, null, null, null, null, null, 257 false); 258 } 259 260 261 262 /** 263 * Creates a new approximate search filter with the provided 264 * information. 265 * 266 * @param attributeType The attribute type for this approximate 267 * filter. 268 * @param assertionValue The assertion value for this approximate 269 * filter. 270 * 271 * @return The constructed approximate search filter. 272 */ 273 public static LDAPFilter createApproximateFilter( 274 String attributeType, 275 ByteString assertionValue) 276 { 277 return new LDAPFilter(FilterType.APPROXIMATE_MATCH, null, null, 278 attributeType, assertionValue, null, null, 279 null, null, false); 280 } 281 282 283 284 /** 285 * Creates a new extensible matching search filter with the provided 286 * information. 287 * 288 * @param matchingRuleID The matching rule ID for this extensible 289 * filter. 290 * @param attributeType The attribute type for this extensible 291 * filter. 292 * @param assertionValue The assertion value for this extensible 293 * filter. 294 * @param dnAttributes The dnAttributes flag for this extensible 295 * filter. 296 * 297 * @return The constructed extensible matching search filter. 298 */ 299 public static LDAPFilter createExtensibleFilter( 300 String matchingRuleID, 301 String attributeType, 302 ByteString assertionValue, 303 boolean dnAttributes) 304 { 305 return new LDAPFilter(FilterType.EXTENSIBLE_MATCH, null, null, 306 attributeType, assertionValue, null, null, 307 null, matchingRuleID, dnAttributes); 308 } 309 310 311 312 /** 313 * Retrieves the filter type for this search filter. 314 * 315 * @return The filter type for this search filter. 316 */ 317 public abstract FilterType getFilterType(); 318 319 320 321 /** 322 * Retrieves the set of subordinate filter components for AND or OR 323 * searches. The contents of the returned list may be altered by 324 * the caller. 325 * 326 * @return The set of subordinate filter components for AND and OR 327 * searches, or {@code null} if this is not an AND or OR 328 * search. 329 */ 330 public abstract ArrayList<RawFilter> getFilterComponents(); 331 332 333 334 /** 335 * Retrieves the subordinate filter component for NOT searches. 336 * 337 * @return The subordinate filter component for NOT searches, or 338 * {@code null} if this is not a NOT search. 339 */ 340 public abstract RawFilter getNOTComponent(); 341 342 343 344 /** 345 * Retrieves the attribute type for this search filter. This will 346 * not be applicable for AND, OR, or NOT filters. 347 * 348 * @return The attribute type for this search filter, or 349 * {@code null} if there is none. 350 */ 351 public abstract String getAttributeType(); 352 353 354 355 /** 356 * Retrieves the assertion value for this search filter. This will 357 * only be applicable for equality, greater or equal, less or equal, 358 * approximate, or extensible matching filters. 359 * 360 * @return The assertion value for this search filter, or 361 * {@code null} if there is none. 362 */ 363 public abstract ByteString getAssertionValue(); 364 365 366 367 /** 368 * Retrieves the subInitial component for this substring filter. 369 * This is only applicable for substring search filters, but even 370 * substring filters might not have a value for this component. 371 * 372 * @return The subInitial component for this substring filter, or 373 * {@code null} if there is none. 374 */ 375 public abstract ByteString getSubInitialElement(); 376 377 378 379 /** 380 * Retrieves the set of subAny elements for this substring filter. 381 * This is only applicable for substring search filters, and even 382 * then may be {@code null} or empty for some substring filters. 383 * 384 * @return The set of subAny elements for this substring filter, or 385 * {@code null} if there are none. 386 */ 387 public abstract ArrayList<ByteString> getSubAnyElements(); 388 389 390 391 /** 392 * Retrieves the subFinal element for this substring filter. This 393 * is not applicable for any other filter type, and may not be 394 * provided even for some substring filters. 395 * 396 * @return The subFinal element for this substring filter, or 397 * {@code null} if there is none. 398 */ 399 public abstract ByteString getSubFinalElement(); 400 401 402 403 /** 404 * Retrieves the matching rule ID for this extensible match filter. 405 * This is not applicable for any other type of filter and may not 406 * be included in some extensible matching filters. 407 * 408 * @return The matching rule ID for this extensible match filter, 409 * or {@code null} if there is none. 410 */ 411 public abstract String getMatchingRuleID(); 412 413 414 415 /** 416 * Retrieves the value of the DN attributes flag for this extensible 417 * match filter, which indicates whether to perform matching on the 418 * components of the DN. This does not apply for any other type of 419 * filter. 420 * 421 * @return The value of the DN attributes flag for this 422 * extensibleMatch filter. 423 */ 424 public abstract boolean getDNAttributes(); 425 426 /** 427 * Writes this protocol op to an ASN.1 output stream. 428 * 429 * @param stream The ASN.1 output stream to write to. 430 * @throws IOException If a problem occurs while writing to the 431 * stream. 432 */ 433 public void write(ASN1Writer stream) throws IOException 434 { 435 FilterType filterType = getFilterType(); 436 switch (filterType) 437 { 438 case AND: 439 case OR: 440 stream.writeStartSequence(filterType.getBERType()); 441 for(RawFilter f : getFilterComponents()) 442 { 443 f.write(stream); 444 } 445 stream.writeEndSequence(); 446 return; 447 case NOT: 448 stream.writeStartSequence(filterType.getBERType()); 449 getNOTComponent().write(stream); 450 stream.writeEndSequence(); 451 return; 452 case EQUALITY: 453 case GREATER_OR_EQUAL: 454 case LESS_OR_EQUAL: 455 case APPROXIMATE_MATCH: 456 stream.writeStartSequence(filterType.getBERType()); 457 stream.writeOctetString(getAttributeType()); 458 stream.writeOctetString(getAssertionValue()); 459 stream.writeEndSequence(); 460 return; 461 case SUBSTRING: 462 stream.writeStartSequence(filterType.getBERType()); 463 stream.writeOctetString(getAttributeType()); 464 465 stream.writeStartSequence(); 466 ByteString subInitialElement = getSubInitialElement(); 467 if (subInitialElement != null) 468 { 469 stream.writeOctetString(TYPE_SUBINITIAL, subInitialElement); 470 } 471 472 ArrayList<ByteString> subAnyElements = getSubAnyElements(); 473 if (subAnyElements != null && !subAnyElements.isEmpty()) 474 { 475 for (ByteString s : subAnyElements) 476 { 477 stream.writeOctetString(TYPE_SUBANY, s); 478 } 479 } 480 481 ByteString subFinalElement = getSubFinalElement(); 482 if (subFinalElement != null) 483 { 484 stream.writeOctetString(TYPE_SUBFINAL, subFinalElement); 485 } 486 stream.writeEndSequence(); 487 488 stream.writeEndSequence(); 489 return; 490 case PRESENT: 491 stream.writeOctetString(filterType.getBERType(), 492 getAttributeType()); 493 return; 494 case EXTENSIBLE_MATCH: 495 stream.writeStartSequence(filterType.getBERType()); 496 497 String matchingRuleID = getMatchingRuleID(); 498 if (matchingRuleID != null) 499 { 500 stream.writeOctetString(TYPE_MATCHING_RULE_ID, 501 matchingRuleID); 502 } 503 504 String attributeType = getAttributeType(); 505 if (attributeType != null) 506 { 507 stream.writeOctetString(TYPE_MATCHING_RULE_TYPE, 508 attributeType); 509 } 510 511 stream.writeOctetString(TYPE_MATCHING_RULE_VALUE, 512 getAssertionValue()); 513 514 if (getDNAttributes()) 515 { 516 stream.writeBoolean(TYPE_MATCHING_RULE_DN_ATTRIBUTES, true); 517 } 518 519 stream.writeEndSequence(); 520 return; 521 default: 522 if (logger.isTraceEnabled()) 523 { 524 logger.trace("Invalid search filter type: %s", 525 filterType); 526 } 527 } 528 } 529 530 /** 531 * Decodes the elements from the provided ASN.1 reader as a 532 * raw search filter. 533 * 534 * @param reader The ASN.1 reader. 535 * 536 * @return The decoded search filter. 537 * 538 * @throws LDAPException If the provided ASN.1 element cannot be 539 * decoded as a raw search filter. 540 */ 541 public static LDAPFilter decode(ASN1Reader reader) 542 throws LDAPException 543 { 544 byte type; 545 try 546 { 547 type = reader.peekType(); 548 } 549 catch(Exception e) 550 { 551 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_NULL.get(); 552 throw new LDAPException(PROTOCOL_ERROR, message); 553 } 554 555 switch (type) 556 { 557 case TYPE_FILTER_AND: 558 case TYPE_FILTER_OR: 559 return decodeCompoundFilter(reader); 560 561 case TYPE_FILTER_NOT: 562 return decodeNotFilter(reader); 563 564 case TYPE_FILTER_EQUALITY: 565 case TYPE_FILTER_GREATER_OR_EQUAL: 566 case TYPE_FILTER_LESS_OR_EQUAL: 567 case TYPE_FILTER_APPROXIMATE: 568 return decodeAVAFilter(reader); 569 570 case TYPE_FILTER_SUBSTRING: 571 return decodeSubstringFilter(reader); 572 573 case TYPE_FILTER_PRESENCE: 574 return decodePresenceFilter(reader); 575 576 case TYPE_FILTER_EXTENSIBLE_MATCH: 577 return decodeExtensibleMatchFilter(reader); 578 579 default: 580 LocalizableMessage message = 581 ERR_LDAP_FILTER_DECODE_INVALID_TYPE.get(type); 582 throw new LDAPException(PROTOCOL_ERROR, message); 583 } 584 } 585 586 /** 587 * Decodes the elements from the provided ASN.1 reader as a compound 588 * filter (i.e. one that holds a set of subordinate filter 589 * components, like AND or OR filters). 590 * 591 * @param reader The ASN.1 reader. 592 * 593 * @return The decoded LDAP search filter. 594 * 595 * @throws LDAPException If a problem occurs while trying to 596 * decode the provided ASN.1 element as a 597 * raw search filter. 598 */ 599 private static LDAPFilter decodeCompoundFilter(ASN1Reader reader) 600 throws LDAPException 601 { 602 byte type; 603 try 604 { 605 type = reader.peekType(); 606 } 607 catch(Exception e) 608 { 609 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_NULL.get(); 610 throw new LDAPException(PROTOCOL_ERROR, message); 611 } 612 613 FilterType filterType; 614 switch (type) 615 { 616 case TYPE_FILTER_AND: 617 filterType = FilterType.AND; 618 break; 619 case TYPE_FILTER_OR: 620 filterType = FilterType.OR; 621 break; 622 default: 623 // This should never happen. 624 if (logger.isTraceEnabled()) 625 { 626 logger.trace("Invalid filter type %x for a " + 627 "compound filter", type); 628 } 629 filterType = null; 630 } 631 632 ArrayList<RawFilter> filterComponents = new ArrayList<>(); 633 try 634 { 635 reader.readStartSequence(); 636 // Should have at least 1 filter 637 // could also be an absolute true/false filter 638 while (reader.hasNextElement()) 639 { 640 filterComponents.add(LDAPFilter.decode(reader)); 641 } 642 reader.readEndSequence(); 643 } 644 catch (LDAPException le) 645 { 646 throw le; 647 } 648 catch (Exception e) 649 { 650 logger.traceException(e); 651 652 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_COMPOUND_COMPONENTS.get(e); 653 throw new LDAPException(PROTOCOL_ERROR, message, e); 654 } 655 656 return new LDAPFilter(filterType, filterComponents, null, null, 657 null, null, null, null, null, false); 658 } 659 660 /** 661 * Decodes the elements from the provided ASN.1 reader as a NOT 662 * filter. 663 * 664 * @param reader The ASN.1 reader. 665 * 666 * @return The decoded LDAP search filter. 667 * 668 * @throws LDAPException If a problem occurs while trying to 669 * decode the provided ASN.1 element as a 670 * raw search filter. 671 */ 672 private static LDAPFilter decodeNotFilter(ASN1Reader reader) 673 throws LDAPException 674 { 675 RawFilter notComponent; 676 try 677 { 678 reader.readStartSequence(); 679 notComponent = decode(reader); 680 reader.readEndSequence(); 681 } 682 catch (LDAPException le) 683 { 684 throw le; 685 } 686 catch (Exception e) 687 { 688 logger.traceException(e); 689 690 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_NOT_COMPONENT.get(e); 691 throw new LDAPException(PROTOCOL_ERROR, message, e); 692 } 693 694 695 return new LDAPFilter(FilterType.NOT, null, notComponent, null, 696 null, null, null, null, null, false); 697 } 698 699 /** 700 * Decodes the elements from the provided ASN.1 read as as a filter 701 * containing an attribute type and an assertion value. This 702 * includes equality, greater or equal, less or equal, and 703 * approximate search filters. 704 * 705 * @param reader The ASN.1 reader. 706 * 707 * @return The decoded LDAP search filter. 708 * 709 * @throws LDAPException If a problem occurs while trying to 710 * decode the provided ASN.1 element as a 711 * raw search filter. 712 */ 713 private static LDAPFilter decodeAVAFilter(ASN1Reader reader) 714 throws LDAPException 715 { 716 byte type; 717 try 718 { 719 type = reader.peekType(); 720 } 721 catch(Exception e) 722 { 723 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_NULL.get(); 724 throw new LDAPException(PROTOCOL_ERROR, message); 725 } 726 727 FilterType filterType; 728 switch (type) 729 { 730 case TYPE_FILTER_EQUALITY: 731 filterType = FilterType.EQUALITY; 732 break; 733 case TYPE_FILTER_GREATER_OR_EQUAL: 734 filterType = FilterType.GREATER_OR_EQUAL; 735 break; 736 case TYPE_FILTER_LESS_OR_EQUAL: 737 filterType = FilterType.LESS_OR_EQUAL; 738 break; 739 case TYPE_FILTER_APPROXIMATE: 740 filterType = FilterType.APPROXIMATE_MATCH; 741 break; 742 default: 743 // This should never happen. 744 if (logger.isTraceEnabled()) 745 { 746 logger.trace("Invalid filter type %x for a " + 747 "type-and-value filter", type); 748 } 749 filterType = null; 750 } 751 752 try 753 { 754 reader.readStartSequence(); 755 } 756 catch (Exception e) 757 { 758 logger.traceException(e); 759 760 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_TV_SEQUENCE.get(e); 761 throw new LDAPException(PROTOCOL_ERROR, message, e); 762 } 763 764 String attributeType; 765 try 766 { 767 attributeType = reader.readOctetStringAsString(); 768 } 769 catch (Exception e) 770 { 771 logger.traceException(e); 772 773 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_TV_TYPE.get(e); 774 throw new LDAPException(PROTOCOL_ERROR, message, e); 775 } 776 777 778 ByteString assertionValue; 779 try 780 { 781 assertionValue = reader.readOctetString(); 782 } 783 catch (Exception e) 784 { 785 logger.traceException(e); 786 787 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_TV_VALUE.get(e); 788 throw new LDAPException(PROTOCOL_ERROR, message, e); 789 } 790 791 try 792 { 793 reader.readEndSequence(); 794 } 795 catch (Exception e) 796 { 797 logger.traceException(e); 798 799 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_TV_SEQUENCE.get(e); 800 throw new LDAPException(PROTOCOL_ERROR, message, e); 801 } 802 803 804 return new LDAPFilter(filterType, null, null, attributeType, 805 assertionValue, null, null, null, null, 806 false); 807 } 808 809 /** 810 * Decodes the elements from the provided ASN.1 reader as a 811 * substring filter. 812 * 813 * @param reader The ASN.1 reader. 814 * 815 * @return The decoded LDAP search filter. 816 * 817 * @throws LDAPException If a problem occurs while trying to 818 * decode the provided ASN.1 element as a 819 * raw search filter. 820 */ 821 private static LDAPFilter decodeSubstringFilter(ASN1Reader reader) 822 throws LDAPException 823 { 824 try 825 { 826 reader.readStartSequence(); 827 } 828 catch (Exception e) 829 { 830 logger.traceException(e); 831 832 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_SUBSTRING_SEQUENCE.get(e); 833 throw new LDAPException(PROTOCOL_ERROR, message, e); 834 } 835 836 837 String attributeType; 838 try 839 { 840 attributeType = reader.readOctetStringAsString(); 841 } 842 catch (Exception e) 843 { 844 logger.traceException(e); 845 846 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_SUBSTRING_TYPE.get(e); 847 throw new LDAPException(PROTOCOL_ERROR, message, e); 848 } 849 850 try 851 { 852 reader.readStartSequence(); 853 } 854 catch (Exception e) 855 { 856 logger.traceException(e); 857 858 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_SUBSTRING_ELEMENTS.get(e); 859 throw new LDAPException(PROTOCOL_ERROR, message, e); 860 } 861 862 863 try 864 { 865 // Make sure we have at least 1 substring 866 reader.peekType(); 867 } 868 catch (Exception e) 869 { 870 LocalizableMessage message = 871 ERR_LDAP_FILTER_DECODE_SUBSTRING_NO_SUBELEMENTS.get(); 872 throw new LDAPException(PROTOCOL_ERROR, message); 873 } 874 875 876 ByteString subInitialElement = null; 877 ByteString subFinalElement = null; 878 ArrayList<ByteString> subAnyElements = null; 879 try 880 { 881 if(reader.hasNextElement() && 882 reader.peekType() == TYPE_SUBINITIAL) 883 { 884 subInitialElement = reader.readOctetString(); 885 } 886 while(reader.hasNextElement() && 887 reader.peekType() == TYPE_SUBANY) 888 { 889 if(subAnyElements == null) 890 { 891 subAnyElements = new ArrayList<>(); 892 } 893 subAnyElements.add(reader.readOctetString()); 894 } 895 if(reader.hasNextElement() && 896 reader.peekType() == TYPE_SUBFINAL) 897 { 898 subFinalElement = reader.readOctetString(); 899 } 900 } 901 catch (Exception e) 902 { 903 logger.traceException(e); 904 905 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_SUBSTRING_VALUES.get(e); 906 throw new LDAPException(PROTOCOL_ERROR, message, e); 907 } 908 909 try 910 { 911 reader.readEndSequence(); 912 } 913 catch (Exception e) 914 { 915 logger.traceException(e); 916 917 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_SUBSTRING_ELEMENTS.get(e); 918 throw new LDAPException(PROTOCOL_ERROR, message, e); 919 } 920 921 try 922 { 923 reader.readEndSequence(); 924 } 925 catch (Exception e) 926 { 927 logger.traceException(e); 928 929 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_SUBSTRING_SEQUENCE.get(e); 930 throw new LDAPException(PROTOCOL_ERROR, message, e); 931 } 932 933 return new LDAPFilter(FilterType.SUBSTRING, null, null, 934 attributeType, null, subInitialElement, 935 subAnyElements, subFinalElement, null, 936 false); 937 } 938 939 /** 940 * Decodes the elements from the provided ASN.1 reader as a 941 * presence filter. 942 * 943 * @param reader The ASN.1 reader. 944 * 945 * @return The decoded LDAP search filter. 946 * 947 * @throws LDAPException If a problem occurs while trying to 948 * decode the provided ASN.1 element as a 949 * raw search filter. 950 */ 951 private static LDAPFilter decodePresenceFilter(ASN1Reader reader) 952 throws LDAPException 953 { 954 String attributeType; 955 try 956 { 957 attributeType = reader.readOctetStringAsString(); 958 } 959 catch (Exception e) 960 { 961 logger.traceException(e); 962 963 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_PRESENCE_TYPE.get(e); 964 throw new LDAPException(PROTOCOL_ERROR, message, e); 965 } 966 967 968 return new LDAPFilter(FilterType.PRESENT, null, null, 969 attributeType, null, null, null, null, null, 970 false); 971 } 972 973 /** 974 * Decodes the elements from the provided ASN.1 reader as an 975 * extensible match filter. 976 * 977 * @param reader The ASN.1 reader. 978 * 979 * @return The decoded LDAP search filter. 980 * 981 * @throws LDAPException If a problem occurs while trying to 982 * decode the provided ASN.1 element as a 983 * raw search filter. 984 */ 985 private static LDAPFilter decodeExtensibleMatchFilter( 986 ASN1Reader reader) throws LDAPException 987 { 988 try 989 { 990 reader.readStartSequence(); 991 } 992 catch (Exception e) 993 { 994 logger.traceException(e); 995 996 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_EXTENSIBLE_SEQUENCE.get(e); 997 throw new LDAPException(PROTOCOL_ERROR, message, e); 998 } 999 1000 1001 ByteString assertionValue; 1002 boolean dnAttributes = false; 1003 String attributeType = null; 1004 String matchingRuleID = null; 1005 try 1006 { 1007 if(reader.peekType() == TYPE_MATCHING_RULE_ID) 1008 { 1009 matchingRuleID = reader.readOctetStringAsString(); 1010 } 1011 if(matchingRuleID == null || 1012 reader.peekType() == TYPE_MATCHING_RULE_TYPE) 1013 { 1014 attributeType = reader.readOctetStringAsString(); 1015 } 1016 assertionValue = reader.readOctetString(); 1017 if(reader.hasNextElement() && 1018 reader.peekType() == TYPE_MATCHING_RULE_DN_ATTRIBUTES) 1019 { 1020 dnAttributes = reader.readBoolean(); 1021 } 1022 } 1023 catch (Exception e) 1024 { 1025 logger.traceException(e); 1026 1027 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_EXTENSIBLE_ELEMENTS.get(e); 1028 throw new LDAPException(PROTOCOL_ERROR, message, e); 1029 } 1030 1031 try 1032 { 1033 reader.readEndSequence(); 1034 } 1035 catch (Exception e) 1036 { 1037 logger.traceException(e); 1038 1039 LocalizableMessage message = ERR_LDAP_FILTER_DECODE_EXTENSIBLE_SEQUENCE.get(e); 1040 throw new LDAPException(PROTOCOL_ERROR, message, e); 1041 } 1042 1043 1044 return new LDAPFilter(FilterType.EXTENSIBLE_MATCH, null, null, 1045 attributeType, assertionValue, null, null, 1046 null, matchingRuleID, dnAttributes); 1047 } 1048 1049 1050 1051 /** 1052 * Converts this raw filter to a search filter that may be used by 1053 * the Directory Server's core processing. 1054 * 1055 * @return The generated search filter. 1056 * 1057 * @throws DirectoryException If a problem occurs while attempting 1058 * to construct the search filter. 1059 */ 1060 public abstract SearchFilter toSearchFilter() 1061 throws DirectoryException; 1062 1063 1064 1065 /** 1066 * Retrieves a string representation of this search filter. 1067 * 1068 * @return A string representation of this search filter. 1069 */ 1070 @Override 1071 public String toString() 1072 { 1073 StringBuilder buffer = new StringBuilder(); 1074 toString(buffer); 1075 return buffer.toString(); 1076 } 1077 1078 1079 1080 /** 1081 * Appends a string representation of this search filter to the 1082 * provided buffer. 1083 * 1084 * @param buffer The buffer to which the information should be 1085 * appended. 1086 */ 1087 public abstract void toString(StringBuilder buffer); 1088 1089 1090 1091 /** 1092 * Appends a properly-cleaned version of the provided value to the 1093 * given buffer so that it can be safely used in string 1094 * representations of this search filter. The formatting changes 1095 * that may be performed will be in compliance with the 1096 * specification in RFC 2254. 1097 * 1098 * @param buffer The buffer to which the "safe" version of the 1099 * value will be appended. 1100 * @param value The value to be appended to the buffer. 1101 */ 1102 public static void valueToFilterString(StringBuilder buffer, 1103 ByteString value) 1104 { 1105 if (value == null) 1106 { 1107 return; 1108 } 1109 1110 1111 // Get the binary representation of the value and iterate through 1112 // it to see if there are any unsafe characters. If there are, 1113 // then escape them and replace them with a two-digit hex 1114 // equivalent. 1115 buffer.ensureCapacity(buffer.length() + value.length()); 1116 for (int i = 0; i < value.length(); i++) 1117 { 1118 byte b = value.byteAt(i); 1119 if (((b & 0x7F) != b) || // Not 7-bit clean 1120 (b <= 0x1F) || // Below the printable character range 1121 (b == 0x28) || // Open parenthesis 1122 (b == 0x29) || // Close parenthesis 1123 (b == 0x2A) || // Asterisk 1124 (b == 0x5C) || // Backslash 1125 (b == 0x7F)) // Delete character 1126 { 1127 buffer.append("\\"); 1128 buffer.append(byteToHex(b)); 1129 } 1130 else 1131 { 1132 buffer.append((char) b); 1133 } 1134 } 1135 } 1136} 1137