001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.server.core.api.interceptor.context; 021 022 023import java.util.HashSet; 024import java.util.Set; 025 026import org.apache.commons.lang3.ArrayUtils; 027import org.apache.directory.api.ldap.model.constants.SchemaConstants; 028import org.apache.directory.api.ldap.model.exception.LdapException; 029import org.apache.directory.api.ldap.model.name.Dn; 030import org.apache.directory.api.ldap.model.schema.AttributeType; 031import org.apache.directory.api.ldap.model.schema.AttributeTypeOptions; 032import org.apache.directory.api.ldap.model.schema.SchemaManager; 033import org.apache.directory.api.ldap.model.schema.SchemaUtils; 034import org.apache.directory.api.ldap.model.schema.UsageEnum; 035import org.apache.directory.server.core.api.CoreSession; 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038 039 040/** 041 * A context used to store the filter used to manage the Attributes the user 042 * ha srequested. It's used by the Lookup, List and Search operations 043 * 044 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 045 */ 046public abstract class FilteringOperationContext extends AbstractOperationContext 047{ 048 /** The LoggerFactory used by this Interceptor */ 049 protected static final Logger LOG = LoggerFactory.getLogger( FilteringOperationContext.class ); 050 051 /** A set containing the returning attributeTypesOptions */ 052 protected Set<AttributeTypeOptions> returningAttributes; 053 054 /** The set of attributes to return as String */ 055 protected String[] returningAttributesString; 056 057 /** A flag set to true if the user has requested all the operational attributes ( "+" )*/ 058 private boolean allOperationalAttributes; 059 060 /** A flag set to true if the user has requested all the user attributes ( "*" ) */ 061 private boolean allUserAttributes; 062 063 /** A flag set to true if the user has requested no attribute to be returned (1.1) */ 064 private boolean noAttributes; 065 066 /** A flag to tell if only the attribute names to be returned. */ 067 protected boolean typesOnly = false; 068 069 070 /** 071 * Creates a new instance of FilteringOperationContext. 072 * 073 * @param session The session to use 074 */ 075 public FilteringOperationContext( CoreSession session ) 076 { 077 // Default to All User Attributes if we don't have any attributes 078 this( session, SchemaConstants.ALL_USER_ATTRIBUTES ); 079 } 080 081 082 /** 083 * Creates a new instance of FilteringOperationContext. 084 * 085 * @param session The session to use 086 * @param dn The Dn 087 */ 088 public FilteringOperationContext( CoreSession session, Dn dn ) 089 { 090 // Default to All User Attributes if we don't have any attributes 091 this( session, dn, SchemaConstants.ALL_USER_ATTRIBUTES ); 092 } 093 094 095 /** 096 * Creates a new instance of LookupOperationContext. 097 * 098 * @param session The session to use 099 * @param returningAttributes The attributes to return 100 */ 101 public FilteringOperationContext( CoreSession session, String... returningAttributes ) 102 { 103 super( session ); 104 105 setReturningAttributes( returningAttributes ); 106 } 107 108 109 /** 110 * Creates a new instance of LookupOperationContext. 111 * 112 * @param session The session to use 113 * @param dn The Dn 114 * @param returningAttributes The attributes to return 115 */ 116 public FilteringOperationContext( CoreSession session, Dn dn, String... returningAttributes ) 117 { 118 super( session, dn ); 119 120 setReturningAttributes( returningAttributes ); 121 } 122 123 124 /** 125 * @return the returningAttributes as a Set of AttributeTypeOptions 126 */ 127 public Set<AttributeTypeOptions> getReturningAttributes() 128 { 129 return returningAttributes; 130 } 131 132 133 /** 134 * @return the returning Attributes, as a array of Strings 135 */ 136 public String[] getReturningAttributesString() 137 { 138 return returningAttributesString; 139 } 140 141 142 /** 143 * Tells if an attribute is present in the list of attribute to return 144 * 145 * @param schemaManager The SchemaManager instance 146 * @param attribute The attribute we are looking for 147 * @return true if the attribute is present 148 */ 149 public boolean contains( SchemaManager schemaManager, String attribute ) 150 { 151 if ( isNoAttributes() ) 152 { 153 return false; 154 } 155 156 try 157 { 158 AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( attribute ); 159 160 return contains( schemaManager, attributeType ); 161 } 162 catch ( LdapException le ) 163 { 164 return false; 165 } 166 } 167 168 169 /** 170 * Tells if an attribute is present in the list of attribute to return 171 * 172 * @param schemaManager The SchemaManager instance 173 * @param attributeType The attributeType we are looking for 174 * @return true if the attribute is present 175 */ 176 public boolean contains( SchemaManager schemaManager, AttributeType attributeType ) 177 { 178 if ( isNoAttributes() ) 179 { 180 return false; 181 } 182 183 if ( ( attributeType.getUsage() == UsageEnum.USER_APPLICATIONS ) && allUserAttributes ) 184 { 185 return true; 186 } 187 188 if ( ( attributeType.getUsage() != UsageEnum.USER_APPLICATIONS ) && allOperationalAttributes ) 189 { 190 return true; 191 } 192 193 // Loop on the returningAttribute, as we have two conditions to check 194 if ( returningAttributes == null ) 195 { 196 return false; 197 } 198 199 // Shortcut 200 if ( returningAttributes.contains( new AttributeTypeOptions( attributeType ) ) ) 201 { 202 return true; 203 } 204 205 // Ok, do it the slow way... 206 for ( AttributeTypeOptions attributeTypeOptions : returningAttributes ) 207 { 208 if ( attributeTypeOptions.getAttributeType().equals( attributeType ) 209 || attributeTypeOptions.getAttributeType().isAncestorOf( attributeType ) ) 210 { 211 return true; 212 } 213 } 214 215 return false; 216 } 217 218 219 public void setReturningAttributes( String... attributeIds ) 220 { 221 if ( ( attributeIds != null ) && ( attributeIds.length != 0 ) && ( attributeIds[0] != null ) ) 222 { 223 // We have something in the list 224 // first, ignore all the unkown AT and convert the strings to 225 // AttributeTypeOptions 226 returningAttributes = new HashSet<>(); 227 Set<String> attributesString = new HashSet<>(); 228 229 Set<AttributeTypeOptions> collectedAttributes = collectAttributeTypes( attributeIds ); 230 231 // If we have valid, '*' or '+' attributes, we can get rid of the NoAttributes flag 232 if ( !collectedAttributes.isEmpty() || allUserAttributes || allOperationalAttributes ) 233 { 234 noAttributes = false; 235 } 236 237 // Now, loop on the list of attributes, and remove all the USER attributes if 238 // we have the '*' attribute, and remove all the OPERATIONAL attributes if we 239 // have the '+' attribute 240 if ( !collectedAttributes.isEmpty() ) 241 { 242 for ( AttributeTypeOptions attributeTypeOption : collectedAttributes ) 243 { 244 if ( attributeTypeOption.getAttributeType().isUser() && !allUserAttributes ) 245 { 246 // We can add the AttributeType in the list of returningAttributeTypes 247 returningAttributes.add( attributeTypeOption ); 248 attributesString.add( attributeTypeOption.getAttributeType().getOid() ); 249 } 250 251 if ( attributeTypeOption.getAttributeType().isOperational() && !allOperationalAttributes ) 252 { 253 // We can add the AttributeType in the list of returningAttributeTypes 254 returningAttributes.add( attributeTypeOption ); 255 attributesString.add( attributeTypeOption.getAttributeType().getOid() ); 256 } 257 } 258 } 259 260 if ( !attributesString.isEmpty() ) 261 { 262 // We have some valid attributes, lt's convert it to String 263 returningAttributesString = attributesString.toArray( ArrayUtils.EMPTY_STRING_ARRAY ); 264 } 265 else 266 { 267 // No valid attributes remaining, that means they were all invalid 268 returningAttributesString = ArrayUtils.EMPTY_STRING_ARRAY; 269 } 270 } 271 else 272 { 273 // Nothing in the list : default to '*' 274 allUserAttributes = true; 275 returningAttributesString = ArrayUtils.EMPTY_STRING_ARRAY; 276 } 277 } 278 279 280 private Set<AttributeTypeOptions> collectAttributeTypes( String... attributesIds ) 281 { 282 Set<AttributeTypeOptions> collectedAttributes = new HashSet<>(); 283 284 if ( ( attributesIds != null ) && ( attributesIds.length != 0 ) ) 285 { 286 for ( String returnAttribute : attributesIds ) 287 { 288 if ( returnAttribute == null ) 289 { 290 continue; 291 } 292 293 if ( returnAttribute.equals( SchemaConstants.NO_ATTRIBUTE ) ) 294 { 295 noAttributes = true; 296 continue; 297 } 298 299 if ( returnAttribute.equals( SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES ) ) 300 { 301 allOperationalAttributes = true; 302 continue; 303 } 304 305 if ( returnAttribute.equals( SchemaConstants.ALL_USER_ATTRIBUTES ) ) 306 { 307 allUserAttributes = true; 308 continue; 309 } 310 311 try 312 { 313 String id = SchemaUtils.stripOptions( returnAttribute ); 314 Set<String> options = SchemaUtils.getOptions( returnAttribute ); 315 316 AttributeType attributeType = session.getDirectoryService() 317 .getSchemaManager().lookupAttributeTypeRegistry( id ); 318 AttributeTypeOptions attrOptions = new AttributeTypeOptions( attributeType, options ); 319 320 collectedAttributes.add( attrOptions ); 321 } 322 catch ( LdapException le ) 323 { 324 LOG.warn( "Requested attribute {} does not exist in the schema, it will be ignored", 325 returnAttribute ); 326 // Unknown attributes should be silently ignored, as RFC 2251 states 327 } 328 } 329 } 330 331 return collectedAttributes; 332 } 333 334 335 /** 336 * @param allOperationalAttributes the allOperationalAttributes to set 337 */ 338 public void setAllOperationalAttributes( boolean allOperationalAttributes ) 339 { 340 this.allOperationalAttributes = allOperationalAttributes; 341 } 342 343 344 /** 345 * @return The flag telling if the "*" attribute has been used 346 */ 347 public boolean isAllUserAttributes() 348 { 349 return allUserAttributes; 350 } 351 352 353 /** 354 * @param allUserAttributes the allUserAttributes to set 355 */ 356 public void setAllUserAttributes( boolean allUserAttributes ) 357 { 358 this.allUserAttributes = allUserAttributes; 359 } 360 361 362 /** 363 * @return The flag telling if the "+" attribute has been used 364 */ 365 public boolean isAllOperationalAttributes() 366 { 367 return allOperationalAttributes; 368 } 369 370 371 /** 372 * @return The flag telling if the "1.1" attribute has been used 373 */ 374 public boolean isNoAttributes() 375 { 376 return noAttributes; 377 } 378 379 380 /** 381 * @param noAttributes the noAttributes to set 382 */ 383 public void setNoAttributes( boolean noAttributes ) 384 { 385 this.noAttributes = noAttributes; 386 } 387 388 389 /** 390 * @return true, if attribute descriptions alone need to be returned 391 */ 392 public boolean isTypesOnly() 393 { 394 return typesOnly; 395 } 396 397 398 /** 399 * @param typesOnly true If we want to get back the attributeType only 400 */ 401 public void setTypesOnly( boolean typesOnly ) 402 { 403 this.typesOnly = typesOnly; 404 } 405 406 407 /** 408 * @see Object#toString() 409 */ 410 @Override 411 public String toString() 412 { 413 StringBuilder sb = new StringBuilder(); 414 415 sb.append( "FilteringOperationContext for Dn '" ); 416 sb.append( dn.getName() ).append( "'" ); 417 418 if ( isTypesOnly() ) 419 { 420 sb.append( ", type only" ); 421 } 422 423 if ( allOperationalAttributes ) 424 { 425 sb.append( ", +" ); 426 } 427 428 if ( allUserAttributes ) 429 { 430 sb.append( ", *" ); 431 } 432 433 if ( noAttributes ) 434 { 435 sb.append( ", 1.1" ); 436 } 437 438 if ( ( returningAttributesString != null ) && ( returningAttributesString.length > 0 ) ) 439 { 440 sb.append( ", attributes : <" ); 441 boolean isFirst = true; 442 443 for ( String returningAttribute : returningAttributesString ) 444 { 445 if ( isFirst ) 446 { 447 isFirst = false; 448 } 449 else 450 { 451 sb.append( ", " ); 452 } 453 454 sb.append( returningAttribute ); 455 } 456 457 sb.append( ">" ); 458 } 459 460 return sb.toString(); 461 } 462}