001/* 002 * Copyright 2008-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2008-2024 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2008-2024 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.matchingrules; 037 038 039 040import com.unboundid.asn1.ASN1OctetString; 041import com.unboundid.ldap.sdk.LDAPException; 042import com.unboundid.util.Debug; 043import com.unboundid.util.Extensible; 044import com.unboundid.util.NotNull; 045import com.unboundid.util.Nullable; 046import com.unboundid.util.ThreadSafety; 047import com.unboundid.util.ThreadSafetyLevel; 048 049 050 051/** 052 * This class provides a common matching rule framework that may be extended by 053 * matching rule implementations in which equality, ordering, and substring 054 * matching can all be made based on byte-for-byte comparisons of the normalized 055 * value, for values that are considered acceptable by the 056 * {@link MatchingRule#normalize} and {@link MatchingRule#normalizeSubstring} 057 * methods. 058 */ 059@Extensible() 060@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 061public abstract class SimpleMatchingRule 062 extends MatchingRule 063{ 064 /** 065 * The serial version UID for this serializable class. 066 */ 067 private static final long serialVersionUID = -7221506185552250694L; 068 069 070 071 /** 072 * {@inheritDoc} 073 */ 074 @Override() 075 public boolean valuesMatch(@NotNull final ASN1OctetString value1, 076 @NotNull final ASN1OctetString value2) 077 throws LDAPException 078 { 079 return normalize(value1).equals(normalize(value2)); 080 } 081 082 083 084 /** 085 * {@inheritDoc} 086 */ 087 @Override() 088 public boolean matchesAnyValue(@NotNull final ASN1OctetString assertionValue, 089 @NotNull final ASN1OctetString[] attributeValues) 090 throws LDAPException 091 { 092 if ((assertionValue == null) || (attributeValues == null) || 093 (attributeValues.length == 0)) 094 { 095 return false; 096 } 097 098 final ASN1OctetString normalizedAssertionValue = normalize(assertionValue); 099 100 for (final ASN1OctetString attributeValue : attributeValues) 101 { 102 try 103 { 104 if (normalizedAssertionValue.equalsIgnoreType( 105 normalize(attributeValue))) 106 { 107 return true; 108 } 109 } 110 catch (final Exception e) 111 { 112 Debug.debugException(e); 113 } 114 } 115 116 return false; 117 } 118 119 120 121 /** 122 * {@inheritDoc} 123 */ 124 @Override() 125 public boolean matchesSubstring(@NotNull final ASN1OctetString value, 126 @Nullable final ASN1OctetString subInitial, 127 @Nullable final ASN1OctetString[] subAny, 128 @Nullable final ASN1OctetString subFinal) 129 throws LDAPException 130 { 131 final byte[] normValue = normalize(value).getValue(); 132 133 int pos = 0; 134 if (subInitial != null) 135 { 136 final byte[] normSubInitial = 137 normalizeSubstring(subInitial, SUBSTRING_TYPE_SUBINITIAL).getValue(); 138 if (normValue.length < normSubInitial.length) 139 { 140 return false; 141 } 142 143 for (int i=0; i < normSubInitial.length; i++) 144 { 145 if (normValue[i] != normSubInitial[i]) 146 { 147 return false; 148 } 149 } 150 151 pos = normSubInitial.length; 152 } 153 154 if (subAny != null) 155 { 156 final byte[][] normSubAny = new byte[subAny.length][]; 157 for (int i=0; i < subAny.length; i++) 158 { 159 normSubAny[i] = 160 normalizeSubstring(subAny[i],SUBSTRING_TYPE_SUBANY).getValue(); 161 } 162 163 for (final byte[] b : normSubAny) 164 { 165 if (b.length == 0) 166 { 167 continue; 168 } 169 170 boolean match = false; 171 final int subEndLength = normValue.length - b.length; 172 while (pos <= subEndLength) 173 { 174 match = true; 175 for (int i=0; i < b.length; i++) 176 { 177 if (normValue[pos+i] != b[i]) 178 { 179 match = false; 180 break; 181 } 182 } 183 184 if (match) 185 { 186 pos += b.length; 187 break; 188 } 189 else 190 { 191 pos++; 192 } 193 } 194 195 if (! match) 196 { 197 return false; 198 } 199 } 200 } 201 202 if (subFinal != null) 203 { 204 final byte[] normSubFinal = 205 normalizeSubstring(subFinal, SUBSTRING_TYPE_SUBFINAL).getValue(); 206 int finalStartPos = normValue.length - normSubFinal.length; 207 if (finalStartPos < pos) 208 { 209 return false; 210 } 211 212 for (int i=0; i < normSubFinal.length; i++,finalStartPos++) 213 { 214 if (normValue[finalStartPos] != normSubFinal[i]) 215 { 216 return false; 217 } 218 } 219 } 220 221 return true; 222 } 223 224 225 226 /** 227 * {@inheritDoc} 228 */ 229 @Override() 230 public int compareValues(@NotNull final ASN1OctetString value1, 231 @NotNull final ASN1OctetString value2) 232 throws LDAPException 233 { 234 final byte[] normValue1 = normalize(value1).getValue(); 235 final byte[] normValue2 = normalize(value2).getValue(); 236 237 final int minLength = Math.min(normValue1.length, normValue2.length); 238 for (int i=0; i < minLength; i++) 239 { 240 final int b1 = normValue1[i] & 0xFF; 241 final int b2 = normValue2[i] & 0xFF; 242 243 if (b1 < b2) 244 { 245 return -1; 246 } 247 else if (b1 > b2) 248 { 249 return 1; 250 } 251 } 252 253 // If we've gotten here, then it means that all of the bytes they had in 254 // common are the same. At this point, the shorter of the two should be 255 // ordered first, or return zero if they're the same length. 256 return normValue1.length - normValue2.length; 257 } 258}