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 2008 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS 026 */ 027package org.opends.server.authorization.dseecompat; 028 029import static org.opends.server.authorization.dseecompat.Aci.*; 030 031import java.util.LinkedList; 032import java.util.List; 033import java.util.Set; 034 035import org.forgerock.opendj.ldap.ByteString; 036import org.opends.server.core.DirectoryServer; 037import org.opends.server.types.Attribute; 038import org.opends.server.types.AttributeType; 039import org.opends.server.types.Attributes; 040import org.opends.server.types.Entry; 041 042/** 043 * This class implements the dseecompat geteffectiverights evaluation. 044 */ 045public class AciEffectiveRights { 046 047 /** 048 * Value used when a aclRights attribute was seen in the search operation 049 * attribute set. 050 */ 051 private static final int ACL_RIGHTS = 0x001; 052 053 /** 054 * Value used when a aclRightsInfo attribute was seen in the search operation 055 * attribute set. 056 */ 057 private static final int ACL_RIGHTS_INFO = 0x002; 058 059 /** 060 * Value used when an ACI has a targattrfilters keyword match and the result 061 * of the access check was a deny. 062 */ 063 private static final int ACL_TARGATTR_DENY_MATCH = 0x004; 064 065 /** 066 * Value used when an ACI has a targattrfilters keyword match and the result 067 * of the access check was an allow. 068 */ 069 private static final int ACL_TARGATTR_ALLOW_MATCH = 0x008; 070 071 /** 072 * String used to build attribute type name when an aclRights result needs to 073 * be added to the return entry. 074 */ 075 private static final String aclRightsAttrStr = "aclRights"; 076 077 /** 078 * String used to build attribute type name when an AclRightsInfo result needs 079 * to be added to the return entry. 080 */ 081 private static final String aclRightsInfoAttrStr = "aclRightsInfo"; 082 083 /** 084 * String used to build attribute type name when an entryLevel rights 085 * attribute type name needs to be added to the return entry. 086 */ 087 private static final String entryLevelStr = "entryLevel"; 088 089 /** 090 * String used to build attribute type name when an attributeLevel rights 091 * attribute type name needs to be added to the return entry. 092 */ 093 private static final String attributeLevelStr = "attributeLevel"; 094 095 /** 096 * The string that is used as the attribute type name when an aclRights 097 * entryLevel evaluation needs to be added to the return entry. 098 */ 099 private static final String aclRightsEntryLevelStr= 100 aclRightsAttrStr + ";" + entryLevelStr; 101 102 /** 103 * The string that is used as the attribute type name when an aclRights 104 * attribute level evaluation needs to be added to the return entry. This 105 * string has the attribute type name used in the evaluation appended to it to 106 * form the final attribute type name. 107 */ 108 private static final String aclRightsAttributeLevelStr= 109 aclRightsAttrStr + ";" + attributeLevelStr; 110 111 /** 112 * The string used to build attribute type name when an attribute level 113 * aclRightsInfo attribute needs to be added to the return entry. This string 114 * has the attribute type name used in the evaluation appended to it to form 115 * the final attribute type name. 116 */ 117 private static final String aclRightsInfoAttrLogsStr = 118 aclRightsInfoAttrStr + ";logs;attributeLevel"; 119 120 /** 121 * The string used to build attribute type name when an entryLevel 122 * aclRightsInfo attribute needs to be added to the return entry. 123 */ 124 private static final String aclRightsInfoEntryLogsStr = 125 aclRightsInfoAttrStr + ";logs;entryLevel"; 126 127 /** 128 * Attribute type used in access evaluation to see if the geteffectiverights 129 * related to the "aclRights" attribute can be performed. 130 */ 131 private static AttributeType aclRights; 132 133 /** 134 * Attribute type used in access evaluation to see if the geteffectiverights 135 * related to the "aclRightsInfo" attribute can be performed. 136 */ 137 private static AttributeType aclRightsInfo; 138 139 /** Attribute type used in the geteffectiverights selfwrite evaluation. */ 140 private static AttributeType dnAttributeType; 141 142 /**The distinguishedName string. */ 143 private static final String dnAttrStr = "distinguishedname"; 144 145 /** 146 * String used to fill in the summary status field when access was allowed. 147 */ 148 private static String ALLOWED="access allowed"; 149 150 /** 151 * String used to fill in the summary status field when access was not 152 * allowed. 153 */ 154 private static String NOT_ALLOWED="access not allowed"; 155 156 /** Evaluated as anonymous user. Used to fill in summary field. */ 157 private static String anonymous="anonymous"; 158 159 /** Format used to build the summary string. */ 160 private static String summaryFormatStr = 161 "acl_summary(%s): %s(%s) on entry/attr(%s, %s) to (%s)" + 162 " (not proxied) ( reason: %s %s)"; 163 164 /** 165 * Strings below represent access denied or allowed evaluation reasons. Used 166 * to fill in the summary status field. Access evaluated an allow ACI. 167 */ 168 private static String EVALUATED_ALLOW="evaluated allow"; 169 170 /** Access evaluated a deny ACI. */ 171 private static String EVALUATED_DENY="evaluated deny"; 172 173 /** Access evaluated deny because there were no allow ACIs. */ 174 private static String NO_ALLOWS="no acis matched the resource"; 175 176 /** Access evaluated deny because no allow or deny ACIs evaluated. */ 177 private static String NO_ALLOWS_MATCHED="no acis matched the subject"; 178 179 /** Access evaluated allow because the clientDN has bypass-acl privileges. */ 180 private static String SKIP_ACI="user has bypass-acl privileges"; 181 182 //TODO add support for the modify-acl privilege? 183 184 /** 185 * Attempts to add the geteffectiverights asked for in the search to the entry 186 * being returned. The two geteffectiverights attributes that can be requested 187 * are: aclRights and aclRightsInfo. The aclRightsInfo attribute will return 188 * a summary string describing in human readable form, a summary of each 189 * requested evaluation result. Here is a sample aclRightsInfo summary: 190 * 191 * acl_summary(main): access_not_allowed(proxy) on 192 * entry/attr(uid=proxieduser,ou=acis,dc=example,dc=com, NULL) to 193 * (uid=superuser,ou=acis,dc=example,dc=com) (not proxied) 194 * (reason: no acis matched the resource ) 195 * 196 * The aclRights attribute will return a simple 197 * string with the following format: 198 * 199 * add:0,delete:0,read:1,write:?,proxy:0 200 * 201 * A 0 represents access denied, 1 access allowed and ? that evaluation 202 * depends on a value of an attribute (targattrfilter keyword present in ACI). 203 * 204 * There are two levels of rights information: 205 * 206 * 1. entryLevel - entry level rights information 207 * 2. attributeLevel - attribute level rights information 208 * 209 * The attribute type names are built up using subtypes: 210 * 211 * aclRights;entryLevel - aclRights entry level presentation 212 * aclRightsInfo;log;entryLevel;{right} - aclRightsInfo entry level 213 * presentation for each type of right (proxy, read, write, add, 214 * delete). 215 * aclRights;attributeLevel;{attributeType name} - aclRights attribute 216 * level presentation for each attribute type requested. 217 * aclRights;attributeLevel;logs;{right};{attributeType name} 218 * - aclRightsInfo attribute level presentation for each attribute 219 * type requested. 220 * 221 * @param handler The ACI handler to use in the evaluation. 222 * @param searchAttributes The attributes requested in the search. 223 * @param container The LDAP operation container to use in the evaluations. 224 * @param e The entry to add the rights attributes to. 225 * @param skipCheck True if ACI evaluation was skipped because bypass-acl 226 * privilege was found. 227 */ 228 public static void addRightsToEntry(AciHandler handler, 229 Set<String> searchAttributes, 230 AciLDAPOperationContainer container, final Entry e, 231 boolean skipCheck) 232 { 233 if (aclRights == null) 234 { 235 aclRights = DirectoryServer.getAttributeTypeOrNull(aclRightsAttrStr.toLowerCase()); 236 } 237 if (aclRightsInfo == null) 238 { 239 aclRightsInfo = DirectoryServer.getAttributeTypeOrNull(aclRightsInfoAttrStr.toLowerCase()); 240 } 241 if (dnAttributeType == null) 242 { 243 dnAttributeType = DirectoryServer.getAttributeTypeOrNull(dnAttrStr); 244 } 245 246 // Check if the attributes aclRights and aclRightsInfo were requested and 247 // add attributes less those two attributes to a new list of attribute 248 // types. 249 List<AttributeType> nonRightsAttrs = new LinkedList<>(); 250 int attrMask = ACI_NULL; 251 for (String a : searchAttributes) 252 { 253 if (aclRightsAttrStr.equalsIgnoreCase(a)) 254 { 255 attrMask |= ACL_RIGHTS; 256 } 257 else if (aclRightsInfoAttrStr.equalsIgnoreCase(a)) 258 { 259 attrMask |= ACL_RIGHTS_INFO; 260 } 261 else 262 { 263 // Check for shorthands for user attributes "*" or operational "+". 264 if ("*".equals(a)) 265 { 266 // Add objectclass. 267 AttributeType ocType = DirectoryServer.getObjectClassAttributeType(); 268 nonRightsAttrs.add(ocType); 269 nonRightsAttrs.addAll(e.getUserAttributes().keySet()); 270 } 271 else if ("+".equals(a)) 272 { 273 nonRightsAttrs.addAll(e.getOperationalAttributes().keySet()); 274 } 275 else 276 { 277 nonRightsAttrs.add(DirectoryServer.getAttributeTypeOrDefault(a.toLowerCase())); 278 } 279 } 280 } 281 282 // If the special geteffectiverights attributes were not found or 283 // the user does not have both bypass-acl privs and is not allowed to 284 // perform rights evaluation -- return the entry unchanged. 285 if (attrMask == ACI_NULL 286 || (!skipCheck && !rightsAccessAllowed(container, handler, attrMask))) 287 { 288 return; 289 } 290 291 // From here on out, geteffectiverights evaluation is being performed and 292 // the container will be manipulated. First set the flag that 293 // geteffectiverights evaluation's underway and to use the authZid for 294 // authorizationDN (they might be the same). 295 container.setGetEffectiveRightsEval(); 296 container.useAuthzid(true); 297 298 // If no attributes were requested return only entryLevel rights, else 299 // return attributeLevel rights and entryLevel rights. Always try and 300 // return the specific attribute rights if they exist. 301 if (!nonRightsAttrs.isEmpty()) 302 { 303 addAttributeLevelRights(container, handler, attrMask, e, nonRightsAttrs, 304 skipCheck, false); 305 } 306 addAttributeLevelRights(container, handler, attrMask, e, container 307 .getSpecificAttributes(), skipCheck, true); 308 addEntryLevelRights(container, handler, attrMask, e, skipCheck); 309 } 310 311 312 313 /** 314 * Perform the attributeLevel rights evaluation on a list of specified 315 * attribute types. Each attribute has an access check done for the following 316 * rights: search, read, compare, add, delete, proxy, selfwrite_add, 317 * selfwrite_delete and write. The special rights, selfwrite_add and 318 * selfwrite_delete, use the authZid as the attribute value to evaluate 319 * against the attribute type being evaluated. The selfwrite_add performs the 320 * access check using the ACI_WRITE_ADD right and selfwrite_delete uses 321 * ACI_WRITE_ADD right. The write right is made complicated by the 322 * targattrfilters keyword, which might depend on an unknown value of an 323 * attribute type. For this case a dummy attribute value is used to try and 324 * determine if a "?" needs to be placed in the rights string. The special 325 * flag ACI_SKIP_PROXY_CHECK is always set, so that proxy evaluation is 326 * bypassed in the Aci Handler's accessAllowed method. 327 * 328 * @param container 329 * The LDAP operation container to use in the evaluations. 330 * @param handler 331 * The Aci Handler to use in the access evaluations. 332 * @param mask 333 * Mask specifying what rights attribute processing to perform 334 * (aclRights or aclRightsInfo or both). 335 * @param retEntry 336 * The entry to return. 337 * @param attrList 338 * The list of attribute types to iterate over. 339 * @param skipCheck 340 * True if ACI evaluation was skipped because bypass-acl privilege 341 * was found. 342 * @param specificAttr 343 * True if this evaluation is result of specific attributes sent in 344 * the request. 345 */ 346 private static void addAttributeLevelRights( 347 AciLDAPOperationContainer container, AciHandler handler, int mask, 348 final Entry retEntry, List<AttributeType> attrList, 349 boolean skipCheck, boolean specificAttr) 350 { 351 if (attrList == null) 352 { 353 return; 354 } 355 356 for(AttributeType a : attrList) { 357 StringBuilder evalInfo=new StringBuilder(); 358 container.setCurrentAttributeType(a); 359 container.setCurrentAttributeValue(null); 360 //Perform search check and append results. 361 container.setRights(ACI_SEARCH | ACI_SKIP_PROXY_CHECK); 362 evalInfo.append(rightsString(container, handler, skipCheck, "search")); 363 addAttrLevelRightsInfo(container, mask, a, retEntry, "search"); 364 evalInfo.append(','); 365 //Perform read check and append results. 366 container.setRights(ACI_READ | ACI_SKIP_PROXY_CHECK); 367 evalInfo.append(rightsString(container, handler, skipCheck, "read")); 368 addAttrLevelRightsInfo(container, mask, a, retEntry, "read"); 369 evalInfo.append(','); 370 //Perform compare and append results. 371 container.setRights(ACI_COMPARE | ACI_SKIP_PROXY_CHECK); 372 evalInfo.append(rightsString(container, handler, skipCheck, "compare")); 373 addAttrLevelRightsInfo(container, mask, a, retEntry, "compare"); 374 evalInfo.append(','); 375 //Write right is more complicated. Create a dummy value and set that as 376 //the attribute's value. Call the special writeRightsString method, rather 377 //than rightsString. 378 ByteString val= ByteString.valueOfUtf8("dum###Val"); 379 container.setCurrentAttributeValue(val); 380 evalInfo.append(attributeLevelWriteRights(container, handler, skipCheck)); 381 addAttrLevelRightsInfo(container, mask, a, retEntry, "write"); 382 evalInfo.append(','); 383 //Perform both selfwrite_add and selfwrite_delete and append results. 384 ByteString val1 = ByteString.valueOfUtf8(container.getClientDN().toString()); 385 if(!specificAttr) 386 { 387 container.setCurrentAttributeType(dnAttributeType); 388 } 389 container.setCurrentAttributeValue(val1); 390 container.setRights(ACI_WRITE_ADD | ACI_SKIP_PROXY_CHECK); 391 evalInfo.append(rightsString(container, handler, skipCheck, 392 "selfwrite_add")); 393 addAttrLevelRightsInfo(container, mask, a, retEntry, "selfwrite_add"); 394 evalInfo.append(','); 395 container.setRights(ACI_WRITE_DELETE | ACI_SKIP_PROXY_CHECK); 396 evalInfo.append(rightsString(container, handler, skipCheck, 397 "selfwrite_delete")); 398 addAttrLevelRightsInfo(container, mask, a, retEntry, "selfwrite_delete"); 399 evalInfo.append(','); 400 container.setCurrentAttributeType(a); 401 container.setCurrentAttributeValue(null); 402 container.setRights(ACI_PROXY | ACI_SKIP_PROXY_CHECK); 403 evalInfo.append(rightsString(container, handler, skipCheck, "proxy")); 404 addAttrLevelRightsInfo(container, mask, a, retEntry, "proxy"); 405 //It is possible that only the aclRightsInfo attribute type was requested. 406 // Only add the aclRights information if the aclRights attribute type was seen. 407 if(hasAttrMask(mask, ACL_RIGHTS)) { 408 String typeStr = aclRightsAttributeLevelStr + ";" + a.getNameOrOID(); 409 AttributeType attributeType = DirectoryServer.getAttributeTypeOrDefault(typeStr); 410 Attribute attr = Attributes.create(attributeType, evalInfo.toString()); 411 //It is possible that the user might have specified the same attributes 412 //in both the search and the specific attribute part of the control. 413 //Only try to add the attribute type if it already hasn't been added. 414 if(!retEntry.hasAttribute(attributeType)) 415 { 416 retEntry.addAttribute(attr,null); 417 } 418 } 419 } 420 container.setCurrentAttributeValue(null); 421 container.setCurrentAttributeType(null); 422 } 423 424 425 426 /** 427 * Perform the attributeLevel write rights evaluation. The issue here is that 428 * an ACI could contain a targattrfilters keyword that matches the attribute 429 * being evaluated. There is no way of knowing if the filter part of the 430 * targattrfilter would be successful or not. So if the ACI that allowed 431 * access, has an targattrfilter keyword, a "?" is used as the result of the 432 * write (depends on attribute value). If the allow ACI doesn't contain a 433 * targattrfilters keyword than a "1" is added. If the ACI denies then a "0" 434 * is added. If the skipCheck flag is true, then a 1 is used for the write 435 * access, since the client DN has bypass privs. 436 * 437 * @param container 438 * The LDAP operation container to use in the evaluations. 439 * @param handler 440 * The Aci Handler to use in the access evaluations. 441 * @param skipCheck 442 * True if ACI evaluation was skipped because bypass-acl privilege 443 * was found. 444 * @return A string representing the rights information. 445 */ 446 private static String attributeLevelWriteRights( 447 AciLDAPOperationContainer container, AciHandler handler, 448 boolean skipCheck) 449 { 450 StringBuilder resString=new StringBuilder(); 451 //If the user has bypass-acl privs and the authzid is equal to the 452 //authorization dn, create a right string with a '1' and a valid 453 //summary. If the user has bypass-acl privs and is querying for 454 //another authzid or they don't have privs -- fall through. 455 if(skipCheck && container.isAuthzidAuthorizationDN()) { 456 resString.append("write").append(":1"); 457 container.setEvaluationResult(EnumEvalReason.SKIP_ACI, null); 458 container.setEvalSummary(createSummary(container, true)); 459 } else { 460 // Reset everything. 461 container.resetEffectiveRightsParams(); 462 //Reset name. 463 container.setTargAttrFiltersAciName(null); 464 container.setRights(ACI_WRITE_ADD | ACI_SKIP_PROXY_CHECK); 465 final boolean addRet = handler.accessAllowed(container) 466 && container.getTargAttrFiltersAciName() == null; 467 container.setRights(ACI_WRITE_DELETE | ACI_SKIP_PROXY_CHECK); 468 final boolean delRet = handler.accessAllowed(container) 469 && container.getTargAttrFiltersAciName() == null; 470 //If both booleans are true, then access was allowed by ACIs that did 471 //not contain targattrfilters. 472 if(addRet && delRet) { 473 resString.append("write").append(":1"); 474 } else { 475 //If there is an ACI name then an ACI with a targattrfilters allowed, 476 //access. A '?' is needed because that evaluation really depends on an 477 //unknown attribute value, not the dummy value. If there is no ACI 478 //then one of the above access checks failed and a '0' is needed. 479 if(container.getTargAttrFiltersAciName() != null) { 480 resString.append("write").append(":?"); 481 } else { 482 resString.append("write").append(":0"); 483 } 484 } 485 } 486 return resString.toString(); 487 } 488 489 490 491 /** 492 * Perform entryLevel rights evaluation. The rights string is added to the 493 * entry if the aclRights attribute was seen in the search's requested 494 * attribute set. 495 * 496 * @param container 497 * The LDAP operation container to use in the evaluations. 498 * @param handler 499 * The Aci Handler to use in the access evaluations. 500 * @param mask 501 * Mask specifying what rights attribute processing to perform 502 * (aclRights or aclRightsInfo or both). 503 * @param retEntry 504 * The entry to return. 505 * @param skipCheck 506 * True if ACI evaluation was skipped because bypass-acl privilege 507 * was found. 508 */ 509 private static void addEntryLevelRights(AciLDAPOperationContainer container, 510 AciHandler handler, int mask, final Entry retEntry, 511 boolean skipCheck) 512 { 513 //Perform access evaluations for rights: add, delete, read, write, proxy. 514 StringBuilder evalInfo=new StringBuilder(); 515 container.setCurrentAttributeType(null); 516 container.setRights(ACI_ADD | ACI_SKIP_PROXY_CHECK); 517 evalInfo.append(rightsString(container, handler, skipCheck, "add")); 518 addEntryLevelRightsInfo(container, mask, retEntry, "add"); 519 evalInfo.append(','); 520 container.setCurrentAttributeType(null); 521 container.setRights(ACI_DELETE | ACI_SKIP_PROXY_CHECK); 522 evalInfo.append(rightsString(container, handler, skipCheck, "delete")); 523 addEntryLevelRightsInfo(container, mask, retEntry, "delete"); 524 evalInfo.append(','); 525 //The read right needs the entry with the full set of attributes. This was 526 //saved in the Aci Handlers maysend method. 527 container.setCurrentAttributeType(null); 528 container.setRights(ACI_READ | ACI_SKIP_PROXY_CHECK); 529 evalInfo.append(rightsString(container, handler, skipCheck, "read")); 530 addEntryLevelRightsInfo(container, mask, retEntry, "read"); 531 evalInfo.append(','); 532 //Switch back to the entry from the Aci Handler's filterentry method. 533 container.setCurrentAttributeType(null); 534 container.setRights(ACI_WRITE| ACI_SKIP_PROXY_CHECK); 535 evalInfo.append(rightsString(container, handler, skipCheck, "write")); 536 addEntryLevelRightsInfo(container, mask, retEntry, "write"); 537 evalInfo.append(','); 538 container.setCurrentAttributeType(null); 539 container.setRights(ACI_PROXY| ACI_SKIP_PROXY_CHECK); 540 evalInfo.append(rightsString(container, handler, skipCheck, "proxy")); 541 addEntryLevelRightsInfo(container, mask, retEntry, "proxy"); 542 if(hasAttrMask(mask, ACL_RIGHTS)) { 543 Attribute attr = Attributes.create(aclRightsEntryLevelStr, evalInfo.toString()); 544 retEntry.addAttribute(attr,null); 545 } 546 } 547 548 /** 549 * Create the rights for aclRights attributeLevel or entryLevel rights 550 * evaluation. The only right needing special treatment is the read right 551 * with no current attribute type set in the container. For that case the 552 * accessAllowedEntry method is used instead of the accessAllowed method. 553 * 554 * @param container The LDAP operation container to use in the evaluations. 555 * @param handler The Aci Handler to use in the access evaluations. 556 * @param skipCheck True if ACI evaluation was skipped because bypass-acl 557 * privilege was found. 558 * @param rightStr String used representation of the right we are evaluating. 559 * @return A string representing the aclRights for the current right and 560 * attribute type/value combinations. 561 */ 562 private static 563 String rightsString(AciLDAPOperationContainer container, 564 AciHandler handler, 565 boolean skipCheck, String rightStr){ 566 StringBuilder resString=new StringBuilder(); 567 container.resetEffectiveRightsParams(); 568 //If the user has bypass-acl privs and the authzid is equal to the 569 //authorization dn, create a right string with a '1' and a valid 570 //summary. If the user has bypass-acl privs and is querying for 571 //another authzid or they don't have privs -- fall through. 572 if(skipCheck && container.isAuthzidAuthorizationDN()) { 573 resString.append(rightStr).append(":1"); 574 container.setEvaluationResult(EnumEvalReason.SKIP_ACI, null); 575 container.setEvalSummary(createSummary(container, true)); 576 } else { 577 boolean ret; 578 //Check if read right check, if so do accessAllowedEntry. 579 if(container.hasRights(ACI_READ) && 580 container.getCurrentAttributeType() == null) 581 { 582 ret=handler.accessAllowedEntry(container); 583 } 584 else 585 { 586 ret=handler.accessAllowed(container); 587 } 588 589 resString.append(rightStr).append(ret ? ":1" : ":0"); 590 } 591 return resString.toString(); 592 } 593 594 595 /** 596 * Check that access is allowed on the aclRights and/or aclRightsInfo 597 * attribute types. 598 * 599 * @param container The LDAP operation container to use in the evaluations. 600 * @param handler The Aci Handler to use in the access evaluations. 601 * @param mask Mask specifying what rights attribute processing to perform 602 * (aclRights or aclRightsInfo or both). 603 * @return True if access to the geteffectiverights attribute types are 604 * allowed. 605 */ 606 private static 607 boolean rightsAccessAllowed(AciLDAPOperationContainer container, 608 AciHandler handler, int mask) { 609 boolean retRight=true, retInfo=true; 610 if(hasAttrMask(mask, ACL_RIGHTS)) { 611 container.setCurrentAttributeType(aclRights); 612 container.setRights(ACI_READ | ACI_SKIP_PROXY_CHECK); 613 retRight=handler.accessAllowed(container); 614 } 615 if(hasAttrMask(mask, ACL_RIGHTS_INFO)) { 616 container.setCurrentAttributeType(aclRightsInfo); 617 container.setRights(ACI_READ | ACI_SKIP_PROXY_CHECK); 618 retInfo=handler.accessAllowed(container); 619 } 620 return retRight && retInfo; 621 } 622 623 624 /** 625 * Add aclRightsInfo attributeLevel information to the entry. This is the 626 * summary string built from the last access check. 627 * 628 * @param container The LDAP operation container to use in the evaluations. 629 * @param mask Mask specifying what rights attribute processing to perform 630 * (aclRights or aclRightsInfo or both). 631 * @param aType The attribute type to use in building the attribute type name. 632 * @param retEntry The entry to add the rights information to. 633 * @param rightStr The string representation of the rights evaluated. 634 */ 635 private static 636 void addAttrLevelRightsInfo(AciLDAPOperationContainer container, int mask, 637 AttributeType aType, Entry retEntry, 638 String rightStr) { 639 640 //Check if the aclRightsInfo attribute was requested. 641 if(hasAttrMask(mask,ACL_RIGHTS_INFO)) { 642 //Build the attribute type. 643 String typeStr= 644 aclRightsInfoAttrLogsStr + ";" + rightStr + ";" + 645 aType.getPrimaryName(); 646 AttributeType attributeType = DirectoryServer.getAttributeTypeOrDefault(typeStr); 647 Attribute attr = Attributes.create(attributeType, container.getEvalSummary()); 648 // The attribute type might have already been added, probably 649 // not but it is possible. 650 if(!retEntry.hasAttribute(attributeType)) 651 { 652 retEntry.addAttribute(attr,null); 653 } 654 } 655 } 656 657 /** 658 * Add aclRightsInfo entryLevel rights to the entry to be returned. This is 659 * the summary string built from the last access check. 660 * 661 * @param container The LDAP operation container to use in the evaluations. 662 * @param mask Mask specifying what rights attribute processing to perform 663 * (aclRights or aclRightsInfo or both). 664 * @param retEntry The entry to add the rights information to. 665 * @param rightStr The string representation of the rights evaluated. 666 */ 667 private static 668 void addEntryLevelRightsInfo(AciLDAPOperationContainer container, int mask, 669 Entry retEntry, 670 String rightStr) { 671 672 //Check if the aclRightsInfo attribute was requested. 673 if(hasAttrMask(mask,ACL_RIGHTS_INFO)) { 674 String typeStr = aclRightsInfoEntryLogsStr + ";" + rightStr; 675 Attribute attr = Attributes.create(typeStr, container.getEvalSummary()); 676 retEntry.addAttribute(attr,null); 677 } 678 } 679 680 /** 681 * Check if the provided mask has a specific rights attr value. 682 * 683 * @param mask The mask with the attribute flags. 684 * @param rightsAttr The rights attr value to check for. 685 * @return True if the mask contains the rights attr value. 686 */ 687 private static boolean hasAttrMask(int mask, int rightsAttr) { 688 return (mask & rightsAttr) != 0; 689 } 690 691 692 /** 693 * Create the summary string used in the aclRightsInfo log string. 694 * 695 * @param evalCtx The evaluation context to gather information from. 696 * @param evalRet The value returned from the access evaluation. 697 * @return A summary of the ACI evaluation 698 */ 699 public static String createSummary(AciEvalContext evalCtx, boolean evalRet) 700 { 701 String srcStr = "main"; 702 String accessStatus = evalRet ? ALLOWED : NOT_ALLOWED; 703 704 //Try and determine what reason string to use. 705 String accessReason = getEvalReason(evalCtx.getEvalReason()); 706 StringBuilder decideAci = 707 getDecidingAci(evalCtx.getEvalReason(), evalCtx.getDecidingAciName()); 708 709 //Only manipulate the evaluation context's targattrfilters ACI name 710 //if not a selfwrite evaluation and the context's targattrfilter match 711 //hashtable is not empty. 712 if(!evalCtx.isTargAttrFilterMatchAciEmpty() && 713 !evalCtx.hasRights(ACI_SELF)) { 714 //If the allow list was empty then access is '0'. 715 if(evalCtx.getAllowList().isEmpty()) { 716 evalCtx.setTargAttrFiltersAciName(null); 717 } else if(evalRet) { 718 //The evaluation returned true, clear the evaluation context's 719 //targattrfilters ACI name only if a deny targattrfilters ACI 720 //was not seen. It could remove the allow. 721 if(!evalCtx.hasTargAttrFiltersMatchOp(ACL_TARGATTR_DENY_MATCH)) 722 { 723 evalCtx.setTargAttrFiltersAciName(null); 724 } 725 } else { 726 //The evaluation returned false. If the reason was an 727 //explicit deny evaluation by a non-targattrfilters ACI, clear 728 //the evaluation context's targattrfilters ACI name since targattrfilter 729 //evaluation is pretty much ignored during geteffectiverights eval. 730 //Else, it was a non-explicit deny, if there is not a targattrfilters 731 //ACI that might have granted access the deny stands, else there is 732 //a targattrfilters ACI that might grant access. 733 if(evalCtx.getEvalReason() == EnumEvalReason.EVALUATED_DENY_ACI) 734 { 735 evalCtx.setTargAttrFiltersAciName(null); 736 } 737 else if(!evalCtx.hasTargAttrFiltersMatchOp(ACL_TARGATTR_ALLOW_MATCH)) 738 { 739 evalCtx.setTargAttrFiltersAciName(null); 740 } 741 } 742 } 743 //Actually build the string. 744 String user=anonymous; 745 if(!evalCtx.getClientDN().isRootDN()) 746 { 747 user=evalCtx.getClientDN().toString(); 748 } 749 String right=evalCtx.rightToString(); 750 AttributeType aType=evalCtx.getCurrentAttributeType(); 751 String attrStr="NULL"; 752 if(aType != null) 753 { 754 attrStr=aType.getPrimaryName(); 755 } 756 if(evalCtx.getTargAttrFiltersAciName() != null) 757 { 758 decideAci.append(", access depends on attr value"); 759 } 760 return String.format(summaryFormatStr, srcStr, accessStatus, 761 right,evalCtx.getResourceDN().toString(),attrStr, user, 762 accessReason, decideAci.toString()); 763 } 764 765 private static String getEvalReason(EnumEvalReason evalReason) 766 { 767 if (evalReason == EnumEvalReason.EVALUATED_ALLOW_ACI) 768 { 769 return EVALUATED_ALLOW; 770 } 771 else if (evalReason == EnumEvalReason.EVALUATED_DENY_ACI) 772 { 773 return EVALUATED_DENY; 774 } 775 else if (evalReason == EnumEvalReason.NO_ALLOW_ACIS) 776 { 777 return NO_ALLOWS; 778 } 779 else if (evalReason == EnumEvalReason.NO_MATCHED_ALLOWS_ACIS) 780 { 781 return NO_ALLOWS_MATCHED; 782 } 783 else if (evalReason == EnumEvalReason.SKIP_ACI) 784 { 785 return SKIP_ACI; 786 } 787 return ""; 788 } 789 790 private static StringBuilder getDecidingAci(EnumEvalReason evalReason, 791 String decidingAciName) 792 { 793 StringBuilder decideAci = new StringBuilder(); 794 if (evalReason == EnumEvalReason.EVALUATED_ALLOW_ACI) 795 { 796 decideAci.append(", deciding_aci: ").append(decidingAciName); 797 } 798 else if (evalReason == EnumEvalReason.EVALUATED_DENY_ACI) 799 { 800 decideAci.append(", deciding_aci: ").append(decidingAciName); 801 } 802 return decideAci; 803 } 804 805 /** 806 * If the specified ACI is in the targattrfilters hashtable contained in the 807 * evaluation context, set the evaluation context's targattrfilters match 808 * variable to either ACL_TARGATTR_DENY_MATCH or ACL_TARGATTR_ALLOW_MATCH 809 * depending on the value of the variable denyAci. 810 * 811 * @param evalCtx The evaluation context to evaluate and save information to. 812 * @param aci The ACI to match. 813 * @param denyAci True if the evaluation was a allow, false if the 814 * evaluation was an deny or the ACI is not in the table. 815 * @return True if the ACI was found in the hashtable. 816 */ 817 public static 818 boolean setTargAttrAci(AciEvalContext evalCtx, Aci aci, boolean denyAci) { 819 if(evalCtx.hasTargAttrFiltersMatchAci(aci)) { 820 int flag = denyAci ? ACL_TARGATTR_DENY_MATCH : ACL_TARGATTR_ALLOW_MATCH; 821 evalCtx.setTargAttrFiltersMatchOp(flag); 822 return true; 823 } 824 return false; 825 } 826 827 /** 828 * Finalizes static variables on shutdown so that we release the memory 829 * associated with them (for the unit tests) and get fresh copies if we're 830 * doing an in-core restart. 831 */ 832 public static void finalizeOnShutdown() { 833 AciEffectiveRights.aclRights = null; 834 AciEffectiveRights.aclRightsInfo = null; 835 AciEffectiveRights.dnAttributeType = null; 836 } 837}