001/* 002 * Copyright 2008-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2008-2020 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-2020 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.ThreadSafety; 045import com.unboundid.util.ThreadSafetyLevel; 046 047 048 049/** 050 * This class provides a common matching rule framework that may be extended by 051 * matching rule implementations in which equality, ordering, and substring 052 * matching can all be made based on byte-for-byte comparisons of the normalized 053 * value, for values that are considered acceptable by the 054 * {@link MatchingRule#normalize} and {@link MatchingRule#normalizeSubstring} 055 * methods. 056 */ 057@Extensible() 058@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 059public abstract class SimpleMatchingRule 060 extends MatchingRule 061{ 062 /** 063 * The serial version UID for this serializable class. 064 */ 065 private static final long serialVersionUID = -7221506185552250694L; 066 067 068 069 /** 070 * {@inheritDoc} 071 */ 072 @Override() 073 public boolean valuesMatch(final ASN1OctetString value1, 074 final ASN1OctetString value2) 075 throws LDAPException 076 { 077 return normalize(value1).equals(normalize(value2)); 078 } 079 080 081 082 /** 083 * {@inheritDoc} 084 */ 085 @Override() 086 public boolean matchesAnyValue(final ASN1OctetString assertionValue, 087 final ASN1OctetString[] attributeValues) 088 throws LDAPException 089 { 090 if ((assertionValue == null) || (attributeValues == null) || 091 (attributeValues.length == 0)) 092 { 093 return false; 094 } 095 096 final ASN1OctetString normalizedAssertionValue = normalize(assertionValue); 097 098 for (final ASN1OctetString attributeValue : attributeValues) 099 { 100 try 101 { 102 if (normalizedAssertionValue.equalsIgnoreType( 103 normalize(attributeValue))) 104 { 105 return true; 106 } 107 } 108 catch (final Exception e) 109 { 110 Debug.debugException(e); 111 } 112 } 113 114 return false; 115 } 116 117 118 119 /** 120 * {@inheritDoc} 121 */ 122 @Override() 123 public boolean matchesSubstring(final ASN1OctetString value, 124 final ASN1OctetString subInitial, 125 final ASN1OctetString[] subAny, 126 final ASN1OctetString subFinal) 127 throws LDAPException 128 { 129 final byte[] normValue = normalize(value).getValue(); 130 131 int pos = 0; 132 if (subInitial != null) 133 { 134 final byte[] normSubInitial = 135 normalizeSubstring(subInitial, SUBSTRING_TYPE_SUBINITIAL).getValue(); 136 if (normValue.length < normSubInitial.length) 137 { 138 return false; 139 } 140 141 for (int i=0; i < normSubInitial.length; i++) 142 { 143 if (normValue[i] != normSubInitial[i]) 144 { 145 return false; 146 } 147 } 148 149 pos = normSubInitial.length; 150 } 151 152 if (subAny != null) 153 { 154 final byte[][] normSubAny = new byte[subAny.length][]; 155 for (int i=0; i < subAny.length; i++) 156 { 157 normSubAny[i] = 158 normalizeSubstring(subAny[i],SUBSTRING_TYPE_SUBANY).getValue(); 159 } 160 161 for (final byte[] b : normSubAny) 162 { 163 if (b.length == 0) 164 { 165 continue; 166 } 167 168 boolean match = false; 169 final int subEndLength = normValue.length - b.length; 170 while (pos <= subEndLength) 171 { 172 match = true; 173 for (int i=0; i < b.length; i++) 174 { 175 if (normValue[pos+i] != b[i]) 176 { 177 match = false; 178 break; 179 } 180 } 181 182 if (match) 183 { 184 pos += b.length; 185 break; 186 } 187 else 188 { 189 pos++; 190 } 191 } 192 193 if (! match) 194 { 195 return false; 196 } 197 } 198 } 199 200 if (subFinal != null) 201 { 202 final byte[] normSubFinal = 203 normalizeSubstring(subFinal, SUBSTRING_TYPE_SUBFINAL).getValue(); 204 int finalStartPos = normValue.length - normSubFinal.length; 205 if (finalStartPos < pos) 206 { 207 return false; 208 } 209 210 for (int i=0; i < normSubFinal.length; i++,finalStartPos++) 211 { 212 if (normValue[finalStartPos] != normSubFinal[i]) 213 { 214 return false; 215 } 216 } 217 } 218 219 return true; 220 } 221 222 223 224 /** 225 * {@inheritDoc} 226 */ 227 @Override() 228 public int compareValues(final ASN1OctetString value1, 229 final ASN1OctetString value2) 230 throws LDAPException 231 { 232 final byte[] normValue1 = normalize(value1).getValue(); 233 final byte[] normValue2 = normalize(value2).getValue(); 234 235 final int minLength = Math.min(normValue1.length, normValue2.length); 236 for (int i=0; i < minLength; i++) 237 { 238 final int b1 = normValue1[i] & 0xFF; 239 final int b2 = normValue2[i] & 0xFF; 240 241 if (b1 < b2) 242 { 243 return -1; 244 } 245 else if (b1 > b2) 246 { 247 return 1; 248 } 249 } 250 251 // If we've gotten here, then it means that all of the bytes they had in 252 // common are the same. At this point, the shorter of the two should be 253 // ordered first, or return zero if they're the same length. 254 return normValue1.length - normValue2.length; 255 } 256}