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 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.extensions; 028 029 030 031 import java.util.Collection; 032 import java.util.LinkedHashSet; 033 import java.util.List; 034 035 import org.opends.server.admin.std.server.EntryDNVirtualAttributeCfg; 036 import org.opends.server.api.VirtualAttributeProvider; 037 import org.opends.server.config.ConfigException; 038 import org.opends.server.core.DirectoryServer; 039 import org.opends.server.core.SearchOperation; 040 import org.opends.server.loggers.debug.DebugTracer; 041 import org.opends.server.types.AttributeType; 042 import org.opends.server.types.AttributeValue; 043 import org.opends.server.types.ByteString; 044 import org.opends.server.types.ByteStringFactory; 045 import org.opends.server.types.ConditionResult; 046 import org.opends.server.types.DebugLogLevel; 047 import org.opends.server.types.DN; 048 import org.opends.server.types.Entry; 049 import org.opends.server.types.InitializationException; 050 import org.opends.server.types.SearchFilter; 051 import org.opends.server.types.SearchScope; 052 import org.opends.server.types.VirtualAttributeRule; 053 054 import static org.opends.server.loggers.debug.DebugLogger.*; 055 import static org.opends.server.util.ServerConstants.*; 056 057 058 059 /** 060 * This class implements a virtual attribute provider that is meant to serve the 061 * entryDN operational attribute as described in draft-zeilenga-ldap-entrydn. 062 */ 063 public class EntryDNVirtualAttributeProvider 064 extends VirtualAttributeProvider<EntryDNVirtualAttributeCfg> 065 { 066 /** 067 * The tracer object for the debug logger. 068 */ 069 private static final DebugTracer TRACER = getTracer(); 070 071 /** 072 * Creates a new instance of this entryDN virtual attribute provider. 073 */ 074 public EntryDNVirtualAttributeProvider() 075 { 076 super(); 077 078 // All initialization should be performed in the 079 // initializeVirtualAttributeProvider method. 080 } 081 082 083 084 /** 085 * {@inheritDoc} 086 */ 087 @Override() 088 public void initializeVirtualAttributeProvider( 089 EntryDNVirtualAttributeCfg configuration) 090 throws ConfigException, InitializationException 091 { 092 // No initialization is required. 093 } 094 095 096 097 /** 098 * {@inheritDoc} 099 */ 100 @Override() 101 public boolean isMultiValued() 102 { 103 return false; 104 } 105 106 107 108 /** 109 * {@inheritDoc} 110 */ 111 @Override() 112 public LinkedHashSet<AttributeValue> getValues(Entry entry, 113 VirtualAttributeRule rule) 114 { 115 LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1); 116 117 String normDNString = entry.getDN().toNormalizedString(); 118 values.add(new AttributeValue(ByteStringFactory.create(normDNString), 119 ByteStringFactory.create(normDNString))); 120 121 return values; 122 } 123 124 125 126 /** 127 * {@inheritDoc} 128 */ 129 @Override() 130 public boolean hasValue(Entry entry, VirtualAttributeRule rule) 131 { 132 // This virtual attribute provider will always generate a value. 133 return true; 134 } 135 136 137 138 /** 139 * {@inheritDoc} 140 */ 141 @Override() 142 public boolean hasValue(Entry entry, VirtualAttributeRule rule, 143 AttributeValue value) 144 { 145 try 146 { 147 String normalizedDN = entry.getDN().toNormalizedString(); 148 String normalizedValue = value.getNormalizedStringValue(); 149 return normalizedDN.equals(normalizedValue); 150 } 151 catch (Exception e) 152 { 153 if (debugEnabled()) 154 { 155 TRACER.debugCaught(DebugLogLevel.ERROR, e); 156 } 157 158 return false; 159 } 160 } 161 162 163 164 /** 165 * {@inheritDoc} 166 */ 167 @Override() 168 public boolean hasAnyValue(Entry entry, VirtualAttributeRule rule, 169 Collection<AttributeValue> values) 170 { 171 String ndnString = entry.getDN().toNormalizedString(); 172 173 AttributeValue v = new AttributeValue(ByteStringFactory.create(ndnString), 174 ByteStringFactory.create(ndnString)); 175 return values.contains(v); 176 } 177 178 179 180 /** 181 * {@inheritDoc} 182 */ 183 @Override() 184 public ConditionResult matchesSubstring(Entry entry, 185 VirtualAttributeRule rule, 186 ByteString subInitial, 187 List<ByteString> subAny, 188 ByteString subFinal) 189 { 190 // DNs cannot be used in substring matching. 191 return ConditionResult.UNDEFINED; 192 } 193 194 195 196 /** 197 * {@inheritDoc} 198 */ 199 @Override() 200 public ConditionResult greaterThanOrEqualTo(Entry entry, 201 VirtualAttributeRule rule, 202 AttributeValue value) 203 { 204 // DNs cannot be used in ordering matching. 205 return ConditionResult.UNDEFINED; 206 } 207 208 209 210 /** 211 * {@inheritDoc} 212 */ 213 @Override() 214 public ConditionResult lessThanOrEqualTo(Entry entry, 215 VirtualAttributeRule rule, 216 AttributeValue value) 217 { 218 // DNs cannot be used in ordering matching. 219 return ConditionResult.UNDEFINED; 220 } 221 222 223 224 /** 225 * {@inheritDoc} 226 */ 227 @Override() 228 public ConditionResult approximatelyEqualTo(Entry entry, 229 VirtualAttributeRule rule, 230 AttributeValue value) 231 { 232 // DNs cannot be used in approximate matching. 233 return ConditionResult.UNDEFINED; 234 } 235 236 237 238 /** 239 * {@inheritDoc}. This virtual attribute will support search operations only 240 * if one of the following is true about the search filter: 241 * <UL> 242 * <LI>It is an equality filter targeting the associated attribute 243 * type.</LI> 244 * <LI>It is an AND filter in which at least one of the components is an 245 * equality filter targeting the associated attribute type.</LI> 246 * <LI>It is an OR filter in which all of the components are equality 247 * filters targeting the associated attribute type.</LI> 248 * </UL> 249 */ 250 @Override() 251 public boolean isSearchable(VirtualAttributeRule rule, 252 SearchOperation searchOperation) 253 { 254 return isSearchable(rule.getAttributeType(), searchOperation.getFilter(), 255 0); 256 } 257 258 259 260 261 /** 262 * Indicates whether the provided search filter is one that may be used with 263 * this virtual attribute provider, optionally operating in a recursive manner 264 * to make the determination. 265 * 266 * @param attributeType The attribute type used to hold the entryDN value. 267 * @param searchFilter The search filter for which to make the 268 * determination. 269 * @param depth The current recursion depth for this processing. 270 * 271 * @return {@code true} if the provided filter may be used with this virtual 272 * attribute provider, or {@code false} if not. 273 */ 274 private boolean isSearchable(AttributeType attributeType, SearchFilter filter, 275 int depth) 276 { 277 switch (filter.getFilterType()) 278 { 279 case AND: 280 if (depth >= MAX_NESTED_FILTER_DEPTH) 281 { 282 return false; 283 } 284 285 for (SearchFilter f : filter.getFilterComponents()) 286 { 287 if (isSearchable(attributeType, f, depth+1)) 288 { 289 return true; 290 } 291 } 292 return false; 293 294 case OR: 295 if (depth >= MAX_NESTED_FILTER_DEPTH) 296 { 297 return false; 298 } 299 300 for (SearchFilter f : filter.getFilterComponents()) 301 { 302 if (! isSearchable(attributeType, f, depth+1)) 303 { 304 return false; 305 } 306 } 307 return true; 308 309 case EQUALITY: 310 return filter.getAttributeType().equals(attributeType); 311 312 default: 313 return false; 314 } 315 } 316 317 318 319 /** 320 * {@inheritDoc} 321 */ 322 @Override() 323 public void processSearch(VirtualAttributeRule rule, 324 SearchOperation searchOperation) 325 { 326 SearchFilter filter = searchOperation.getFilter(); 327 LinkedHashSet<DN> dnSet = new LinkedHashSet<DN>(); 328 extractDNs(rule.getAttributeType(), filter, dnSet); 329 330 if (dnSet.isEmpty()) 331 { 332 return; 333 } 334 335 DN baseDN = searchOperation.getBaseDN(); 336 SearchScope scope = searchOperation.getScope(); 337 for (DN dn : dnSet) 338 { 339 if (! dn.matchesBaseAndScope(baseDN, scope)) 340 { 341 continue; 342 } 343 344 try 345 { 346 Entry entry = DirectoryServer.getEntry(dn); 347 if ((entry != null) && filter.matchesEntry(entry)) 348 { 349 searchOperation.returnEntry(entry, null); 350 } 351 } 352 catch (Exception e) 353 { 354 if (debugEnabled()) 355 { 356 TRACER.debugCaught(DebugLogLevel.ERROR, e); 357 } 358 } 359 } 360 } 361 362 363 364 /** 365 * Extracts the user DNs from the provided filter, operating recursively as 366 * necessary, and adds them to the provided set. 367 * 368 * @param attributeType The attribute type holding the entryDN value. 369 * @param filter The search filter to be processed. 370 * @param dnSet The set into which the identified DNs should be 371 * placed. 372 */ 373 private void extractDNs(AttributeType attributeType, SearchFilter filter, 374 LinkedHashSet<DN> dnSet) 375 { 376 switch (filter.getFilterType()) 377 { 378 case AND: 379 case OR: 380 for (SearchFilter f : filter.getFilterComponents()) 381 { 382 extractDNs(attributeType, f, dnSet); 383 } 384 break; 385 386 case EQUALITY: 387 if (filter.getAttributeType().equals(attributeType)) 388 { 389 try 390 { 391 dnSet.add(DN.decode(filter.getAssertionValue().getValue())); 392 } 393 catch (Exception e) 394 { 395 if (debugEnabled()) 396 { 397 TRACER.debugCaught(DebugLogLevel.ERROR, e); 398 } 399 } 400 } 401 break; 402 } 403 } 404 } 405