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.*; 030import static org.opends.server.authorization.dseecompat.AciHandler.*; 031import static org.opends.server.util.ServerConstants.*; 032 033import java.net.InetAddress; 034import java.security.cert.Certificate; 035import java.util.Collection; 036import java.util.HashMap; 037import java.util.List; 038 039import org.forgerock.opendj.ldap.ByteString; 040import org.opends.server.api.ClientConnection; 041import org.opends.server.api.Group; 042import org.opends.server.controls.GetEffectiveRightsRequestControl; 043import org.opends.server.core.AddOperation; 044import org.opends.server.core.SearchOperation; 045import org.opends.server.protocols.ldap.LDAPClientConnection; 046import org.opends.server.types.*; 047 048/** 049 * The AciContainer class contains all of the needed information to perform 050 * both target match and evaluate an ACI. Target matching is the process 051 * of testing if an ACI is applicable to an operation, and evaluation is 052 * the actual access evaluation of the ACI. 053 */ 054public abstract class AciContainer 055implements AciTargetMatchContext, AciEvalContext { 056 057 /** 058 * The allow and deny lists. 059 */ 060 private List<Aci> denyList, allowList; 061 062 /** 063 * The attribute type in the resource entry currently being evaluated. 064 */ 065 private AttributeType attributeType; 066 067 /** 068 * The attribute type value in the resource entry currently being 069 * evaluated. 070 */ 071 private ByteString attributeValue; 072 073 /** 074 * True if this is the first attribute type in the resource entry being 075 * evaluated. 076 */ 077 private boolean isFirst; 078 079 /** 080 * True if an entry test rule was seen during target matching of an ACI 081 * entry. A entry test rule is an ACI with targetattrs target keyword. 082 */ 083 private boolean isEntryTestRule; 084 085 /** 086 * The right mask to use in the evaluation of the LDAP operation. 087 */ 088 private int rightsMask; 089 090 /** 091 * The entry being evaluated (resource entry). 092 */ 093 private Entry resourceEntry; 094 095 /** 096 * The client connection information. 097 */ 098 private final ClientConnection clientConnection; 099 100 /** 101 * The operation being evaluated. 102 */ 103 private final Operation operation; 104 105 /** 106 * True if a targattrfilters match was found. 107 */ 108 private boolean targAttrFiltersMatch; 109 110 /** 111 * The authorization entry currently being evaluated. If proxied 112 * authorization is being used and the handler is doing a proxy access 113 * check, then this entry will switched to the original authorization entry 114 * rather than the proxy ID entry. If the check succeeds, it will be 115 * switched back for non-proxy access checking. If proxied authentication 116 * is not being used then this entry never changes. 117 */ 118 private Entry authorizationEntry; 119 120 /** 121 * True if proxied authorization is being used. 122 */ 123 private boolean proxiedAuthorization; 124 125 /** 126 * Used by proxied authorization processing. True if the entry has already 127 * been processed by an access proxy check. Some operations might perform 128 * several access checks on the same entry (modify DN), this 129 * flag is used to bypass the proxy check after the initial evaluation. 130 */ 131 private boolean seenEntry; 132 133 /** 134 * True if geteffectiverights evaluation is in progress. 135 */ 136 private boolean isGetEffectiveRightsEval; 137 138 /** 139 * True if the operation has a geteffectiverights control. 140 */ 141 private boolean hasGetEffectiveRightsControl; 142 143 /** 144 * The geteffectiverights authzID in DN format. 145 */ 146 private DN authzid; 147 148 /** 149 * True if the authZid should be used as the client DN, only used in 150 * geteffectiverights evaluation. 151 */ 152 private boolean useAuthzid; 153 154 /** 155 * The list of specific attributes to get rights for, in addition to 156 * any attributes requested in the search. 157 */ 158 private List<AttributeType> specificAttrs; 159 160 /** 161 * Table of ACIs that have targattrfilter keywords that matched. Used 162 * in geteffectiverights attributeLevel write evaluation. 163 */ 164 private final HashMap<Aci,Aci> targAttrFilterAcis = new HashMap<>(); 165 166 /** 167 * The name of a ACI that decided an evaluation and contained a 168 * targattrfilter keyword. Used in geteffectiverights attributeLevel 169 * write evaluation. 170 */ 171 private String targAttrFiltersAciName; 172 173 /** 174 * Value that is used to store the allow/deny result of a deciding ACI 175 * containing a targattrfilter keyword. Used in geteffectiverights 176 * attributeLevel write evaluation. 177 */ 178 private int targAttrMatch; 179 180 /** 181 * The ACI that decided the last evaluation. Used in geteffectiverights 182 * loginfo processing. 183 */ 184 private Aci decidingAci; 185 186 /** 187 * The reason the last evaluation decision was made. Used both 188 * in geteffectiverights loginfo processing and attributeLevel write 189 * evaluation. 190 */ 191 private EnumEvalReason evalReason; 192 193 /** 194 * A summary string holding the last evaluation information in textual 195 * format. Used in geteffectiverights loginfo processing. 196 */ 197 private String summaryString; 198 199 /** 200 * Flag used to determine if ACI all attributes target matched. 201 */ 202 private int evalAllAttributes; 203 204 /** 205 * String used to hold a control OID string. 206 */ 207 private String controlOID; 208 209 /** 210 * String used to hold an extended operation OID string. 211 */ 212 private String extOpOID; 213 214 /** 215 * AuthenticationInfo class to use. 216 */ 217 private AuthenticationInfo authInfo; 218 219 /** 220 * This constructor is used by all currently supported LDAP operations 221 * except the generic access control check that can be used by 222 * plugins. 223 * 224 * @param operation The Operation object being evaluated and target 225 * matching. 226 * 227 * @param rights The rights array to use in evaluation and target matching. 228 * 229 * @param entry The current entry being evaluated and target matched. 230 */ 231 protected AciContainer(Operation operation, int rights, Entry entry) { 232 this.resourceEntry=entry; 233 this.operation=operation; 234 this.clientConnection=operation.getClientConnection(); 235 this.authInfo = clientConnection.getAuthenticationInfo(); 236 237 //If the proxied authorization control was processed, then the operation 238 //will contain an attachment containing the original authorization entry. 239 final Entry origAuthorizationEntry = (Entry) operation.getAttachment(ORIG_AUTH_ENTRY); 240 this.proxiedAuthorization = origAuthorizationEntry != null; 241 this.authorizationEntry=operation.getAuthorizationEntry(); 242 243 //The ACI_READ right at constructor time can only be the result of the 244 //AciHandler.filterEntry method. This method processes the 245 //geteffectiverights control, so it needs to check for it. There are 246 //two other checks done, because the resource entry passed to that method 247 //is filtered (it may not contain enough attribute information 248 //to evaluate correctly). See the the comments below. 249 if (rights == ACI_READ) { 250 //Checks if a geteffectiverights control was sent and 251 //sets up the structures needed. 252 GetEffectiveRightsRequestControl getEffectiveRightsControl = 253 (GetEffectiveRightsRequestControl) 254 operation.getAttachment(OID_GET_EFFECTIVE_RIGHTS); 255 if (getEffectiveRightsControl != null 256 && operation instanceof SearchOperation) 257 { 258 hasGetEffectiveRightsControl = true; 259 if (getEffectiveRightsControl.getAuthzDN() == null) { 260 this.authzid = getClientDN(); 261 } else { 262 this.authzid = getEffectiveRightsControl.getAuthzDN(); 263 } 264 this.specificAttrs = getEffectiveRightsControl.getAttributes(); 265 } 266 267 //If an ACI evaluated because of an Targetattr="*", then the 268 //AciHandler.maySend method signaled this via adding this attachment 269 //string. 270 String allUserAttrs= 271 (String)operation.getAttachment(ALL_USER_ATTRS_MATCHED); 272 if(allUserAttrs != null) 273 { 274 evalAllAttributes |= ACI_USER_ATTR_STAR_MATCHED; 275 } 276 //If an ACI evaluated because of an Targetattr="+", then the 277 //AciHandler.maySend method signaled this via adding this attachment 278 //string. 279 String allOpAttrs=(String)operation.getAttachment(ALL_OP_ATTRS_MATCHED); 280 if(allOpAttrs != null) 281 { 282 evalAllAttributes |= ACI_OP_ATTR_PLUS_MATCHED; 283 } 284 } 285 286 //Reference the current authorization entry, so it can be put back 287 //if an access proxy check was performed. 288 this.rightsMask = rights; 289 } 290 291 /** 292 * This constructor is used by the generic access control check. 293 * 294 * @param operation The operation to use in the access evaluation. 295 * @param e The entry to check access for. 296 * @param authInfo The authentication information to use in the evaluation. 297 * @param rights The rights to check access of. 298 */ 299 protected AciContainer(Operation operation, Entry e, 300 AuthenticationInfo authInfo, 301 int rights) { 302 this.resourceEntry=e; 303 this.operation=operation; 304 this.clientConnection=operation.getClientConnection(); 305 this.authInfo = authInfo; 306 this.authorizationEntry = authInfo.getAuthorizationEntry(); 307 this.rightsMask = rights; 308 } 309 /** 310 * Returns true if an entry has already been processed by an access proxy 311 * check. 312 * 313 * @return True if an entry has already been processed by an access proxy 314 * check. 315 */ 316 public boolean hasSeenEntry() { 317 return this.seenEntry; 318 } 319 320 /** 321 * Set to true if an entry has already been processed by an access proxy 322 * check. 323 * 324 * @param val The value to set the seenEntry boolean to. 325 */ 326 public void setSeenEntry(boolean val) { 327 this.seenEntry=val; 328 } 329 330 /** {@inheritDoc} */ 331 @Override 332 public boolean isProxiedAuthorization() { 333 return this.proxiedAuthorization; 334 } 335 336 /** {@inheritDoc} */ 337 @Override 338 public boolean isGetEffectiveRightsEval() { 339 return this.isGetEffectiveRightsEval; 340 } 341 342 /** 343 * The container is going to be used in a geteffectiverights evaluation, set 344 * the flag isGetEffectiveRightsEval to true. 345 */ 346 public void setGetEffectiveRightsEval() { 347 this.isGetEffectiveRightsEval=true; 348 } 349 350 /** 351 * Return true if the container is being used in a geteffectiverights 352 * evaluation. 353 * 354 * @return True if the container is being used in a geteffectiverights 355 * evaluation. 356 */ 357 public boolean hasGetEffectiveRightsControl() { 358 return this.hasGetEffectiveRightsControl; 359 } 360 361 /** 362 * Use the DN from the geteffectiverights control's authzId as the 363 * client DN, rather than the authorization entry's DN. 364 * 365 * @param v The valued to set the useAuthzid to. 366 */ 367 public void useAuthzid(boolean v) { 368 this.useAuthzid=v; 369 } 370 371 /** 372 * Return the list of additional attributes specified in the 373 * geteffectiverights control. 374 * 375 * @return The list of attributes to return rights information about in the 376 * entry. 377 */ 378 public List<AttributeType> getSpecificAttributes() { 379 return this.specificAttrs; 380 } 381 382 /** {@inheritDoc} */ 383 @Override 384 public void addTargAttrFiltersMatchAci(Aci aci) { 385 this.targAttrFilterAcis.put(aci, aci); 386 } 387 388 /** {@inheritDoc} */ 389 @Override 390 public boolean hasTargAttrFiltersMatchAci(Aci aci) { 391 return this.targAttrFilterAcis.containsKey(aci); 392 } 393 394 /** {@inheritDoc} */ 395 @Override 396 public boolean isTargAttrFilterMatchAciEmpty() { 397 return this.targAttrFilterAcis.isEmpty(); 398 } 399 400 /** 401 * Reset the values used by the geteffectiverights evaluation to 402 * original values. The geteffectiverights evaluation uses the same container 403 * repeatedly for different rights evaluations (read, write, proxy,...) and 404 * this method resets variables that are specific to a single evaluation. 405 */ 406 public void resetEffectiveRightsParams() { 407 this.targAttrFilterAcis.clear(); 408 this.decidingAci=null; 409 this.evalReason=null; 410 this.targAttrFiltersMatch=false; 411 this.summaryString=null; 412 this.targAttrMatch=0; 413 } 414 415 /** {@inheritDoc} */ 416 @Override 417 public void setTargAttrFiltersAciName(String name) { 418 this.targAttrFiltersAciName=name; 419 } 420 421 /** {@inheritDoc} */ 422 @Override 423 public String getTargAttrFiltersAciName() { 424 return this.targAttrFiltersAciName; 425 } 426 427 /** {@inheritDoc} */ 428 @Override 429 public void setTargAttrFiltersMatchOp(int flag) { 430 this.targAttrMatch |= flag; 431 } 432 433 /** {@inheritDoc} */ 434 @Override 435 public boolean hasTargAttrFiltersMatchOp(int flag) { 436 return (this.targAttrMatch & flag) != 0; 437 } 438 439 /** {@inheritDoc} */ 440 @Override 441 public String getDecidingAciName() { 442 if(this.decidingAci != null) { 443 return this.decidingAci.getName(); 444 } 445 return null; 446 } 447 448 /** {@inheritDoc} */ 449 @Override 450 public void setEvaluationResult(EnumEvalReason reason, Aci decidingAci) 451 { 452 this.evalReason = reason; 453 this.decidingAci = decidingAci; 454 } 455 456 /** {@inheritDoc} */ 457 @Override 458 public EnumEvalReason getEvalReason() { 459 return this.evalReason; 460 } 461 462 /** {@inheritDoc} */ 463 @Override 464 public void setEvalSummary(String summary) { 465 this.summaryString=summary; 466 } 467 468 /** {@inheritDoc} */ 469 @Override 470 public String getEvalSummary() { 471 return this.summaryString; 472 } 473 474 /** 475 * Returns true if the geteffectiverights control's authZid DN is equal to the 476 * authorization entry's DN. 477 * 478 * @return True if the authZid is equal to the authorization entry's DN. 479 */ 480 public boolean isAuthzidAuthorizationDN() { 481 return this.authzid.equals(this.authorizationEntry.getName()); 482 } 483 484 /** {@inheritDoc} */ 485 @Override 486 public void setDenyList(List<Aci> denys) { 487 denyList=denys; 488 } 489 490 /** {@inheritDoc} */ 491 @Override 492 public void setAllowList(List<Aci> allows) { 493 allowList=allows; 494 } 495 496 /** {@inheritDoc} */ 497 @Override 498 public AttributeType getCurrentAttributeType() { 499 return attributeType; 500 } 501 502 /** {@inheritDoc} */ 503 @Override 504 public ByteString getCurrentAttributeValue() { 505 return attributeValue; 506 } 507 508 /** {@inheritDoc} */ 509 @Override 510 public void setCurrentAttributeType(AttributeType type) { 511 attributeType=type; 512 } 513 514 /** {@inheritDoc} */ 515 @Override 516 public void setCurrentAttributeValue(ByteString value) { 517 attributeValue=value; 518 } 519 520 /** {@inheritDoc} */ 521 @Override 522 public boolean isFirstAttribute() { 523 return isFirst; 524 } 525 526 /** {@inheritDoc} */ 527 @Override 528 public void setIsFirstAttribute(boolean val) { 529 isFirst=val; 530 } 531 532 /** {@inheritDoc} */ 533 @Override 534 public boolean hasEntryTestRule() { 535 return isEntryTestRule; 536 } 537 538 /** {@inheritDoc} */ 539 @Override 540 public void setEntryTestRule(boolean val) { 541 isEntryTestRule=val; 542 } 543 544 /** {@inheritDoc} */ 545 @Override 546 public Entry getResourceEntry() { 547 return resourceEntry; 548 } 549 550 /** {@inheritDoc} */ 551 @Override 552 public Entry getClientEntry() { 553 return this.authorizationEntry; 554 } 555 556 /** {@inheritDoc} */ 557 @Override 558 public List<Aci> getDenyList() { 559 return denyList; 560 } 561 562 /** {@inheritDoc} */ 563 @Override 564 public List<Aci> getAllowList() { 565 return allowList; 566 } 567 568 /** {@inheritDoc} */ 569 @Override 570 public boolean isDenyEval() { 571 return EnumEvalReason.NO_ALLOW_ACIS.equals(evalReason) 572 || EnumEvalReason.EVALUATED_DENY_ACI.equals(evalReason); 573 } 574 575 /** {@inheritDoc} */ 576 @Override 577 public boolean isAnonymousUser() { 578 return !authInfo.isAuthenticated(); 579 } 580 581 /** {@inheritDoc} */ 582 @Override 583 public DN getClientDN() { 584 if(this.useAuthzid) 585 { 586 return this.authzid; 587 } 588 else if (this.authorizationEntry != null) 589 { 590 return this.authorizationEntry.getName(); 591 } 592 return DN.rootDN(); 593 } 594 595 /** {@inheritDoc} */ 596 @Override 597 public DN getResourceDN() { 598 return resourceEntry.getName(); 599 } 600 601 /** 602 * {@inheritDoc} 603 * <p> 604 * JNR: I find the implementation in this method dubious. 605 * 606 * @see EnumRight#hasRights(int, int) 607 */ 608 @Override 609 public boolean hasRights(int rights) { 610 return (this.rightsMask & rights) != 0; 611 } 612 613 /** {@inheritDoc} */ 614 @Override 615 public int getRights() { 616 return this.rightsMask; 617 } 618 619 /** {@inheritDoc} */ 620 @Override 621 public void setRights(int rights) { 622 this.rightsMask=rights; 623 } 624 625 /** {@inheritDoc} */ 626 @Override 627 public String getHostName() { 628 return clientConnection.getRemoteAddress().getCanonicalHostName(); 629 } 630 631 /** {@inheritDoc} */ 632 @Override 633 public InetAddress getRemoteAddress() { 634 return clientConnection.getRemoteAddress(); 635 } 636 637 /** {@inheritDoc} */ 638 @Override 639 public boolean isAddOperation() { 640 return operation instanceof AddOperation; 641 } 642 643 /** {@inheritDoc} */ 644 @Override 645 public void setTargAttrFiltersMatch(boolean v) { 646 this.targAttrFiltersMatch=v; 647 } 648 649 /** {@inheritDoc} */ 650 @Override 651 public boolean getTargAttrFiltersMatch() { 652 return targAttrFiltersMatch; 653 } 654 655 /** {@inheritDoc} */ 656 @Override 657 public String getControlOID() { 658 return controlOID; 659 } 660 661 /** {@inheritDoc} */ 662 @Override 663 public String getExtOpOID() { 664 return extOpOID; 665 } 666 667 /** 668 * Set the the controlOID value to the specified oid string. 669 * 670 * @param oid The control oid string. 671 */ 672 protected void setControlOID(String oid) { 673 this.controlOID=oid; 674 } 675 676 677 /** 678 * Set the extended operation OID value to the specified oid string. 679 * 680 * @param oid The extended operation oid string. 681 */ 682 protected void setExtOpOID(String oid) { 683 this.extOpOID=oid; 684 } 685 686 /** {@inheritDoc} */ 687 @Override 688 public EnumEvalResult hasAuthenticationMethod(EnumAuthMethod authMethod, 689 String saslMech) { 690 EnumEvalResult matched=EnumEvalResult.FALSE; 691 692 if(authMethod==EnumAuthMethod.AUTHMETHOD_NONE) { 693 /* 694 * None actually means any, in that we don't care what method was used. 695 * This doesn't seem very intuitive or useful, but that's the way it is. 696 */ 697 matched = EnumEvalResult.TRUE; 698 } else { 699 // Some kind of authentication is required. 700 if(authInfo.isAuthenticated()) { 701 if(authMethod==EnumAuthMethod.AUTHMETHOD_SIMPLE) { 702 if(authInfo.hasAuthenticationType(AuthenticationType.SIMPLE)) { 703 matched = EnumEvalResult.TRUE; 704 } 705 } else if(authMethod == EnumAuthMethod.AUTHMETHOD_SSL) { 706 /* 707 * This means authentication using a certificate over TLS. 708 * 709 * We check the following: 710 * - SASL EXTERNAL has been used, and 711 * - TLS is the security provider, and 712 * - The client provided a certificate. 713 */ 714 if (authInfo.hasAuthenticationType(AuthenticationType.SASL) 715 && authInfo.hasSASLMechanism(saslMech) 716 && clientConnection instanceof LDAPClientConnection) { 717 LDAPClientConnection lc = (LDAPClientConnection) clientConnection; 718 Certificate[] certChain = lc.getClientCertificateChain(); 719 if (certChain.length != 0) { 720 matched = EnumEvalResult.TRUE; 721 } 722 } 723 } else { 724 // A particular SASL mechanism. 725 if (authInfo.hasAuthenticationType(AuthenticationType.SASL) && 726 authInfo.hasSASLMechanism(saslMech)) { 727 matched = EnumEvalResult.TRUE; 728 } 729 } 730 } 731 } 732 return matched; 733 } 734 735 /** {@inheritDoc} */ 736 @Override 737 public boolean isMemberOf(Group<?> group) { 738 try { 739 if(useAuthzid) { 740 return group.isMember(this.authzid); 741 } 742 Entry e = getClientEntry(); 743 if (e != null) { 744 return group.isMember(e); 745 } 746 return group.isMember(getClientDN()); 747 } catch (DirectoryException ex) { 748 return false; 749 } 750 } 751 752 /** 753 * {@inheritDoc} 754 * <p> 755 * JNR: I find the implementation in this method dubious. 756 * 757 * @see EnumRight#getEnumRight(int) 758 */ 759 @Override 760 public String rightToString() { 761 if(hasRights(ACI_SEARCH)) 762 { 763 return "search"; 764 } 765 else if(hasRights(ACI_COMPARE)) 766 { 767 return "compare"; 768 } 769 else if(hasRights(ACI_READ)) 770 { 771 return "read"; 772 } 773 else if(hasRights(ACI_DELETE)) 774 { 775 return "delete"; 776 } 777 else if(hasRights(ACI_ADD)) 778 { 779 return "add"; 780 } 781 else if(hasRights(ACI_WRITE)) 782 { 783 return "write"; 784 } 785 else if(hasRights(ACI_PROXY)) 786 { 787 return "proxy"; 788 } 789 else if(hasRights(ACI_IMPORT)) 790 { 791 return "import"; 792 } 793 else if(hasRights(ACI_EXPORT)) 794 { 795 return "export"; 796 } 797 else if(hasRights(ACI_WRITE) && 798 hasRights(ACI_SELF)) 799 { 800 return "selfwrite"; 801 } 802 return null; 803 } 804 805 /** {@inheritDoc} */ 806 @Override 807 public void setEvalUserAttributes(int v) { 808 if(rightsMask == ACI_READ) { 809 if(v == ACI_FOUND_USER_ATTR_RULE) { 810 evalAllAttributes |= ACI_FOUND_USER_ATTR_RULE; 811 evalAllAttributes &= ~ACI_USER_ATTR_STAR_MATCHED; 812 } 813 else 814 { 815 evalAllAttributes |= ACI_USER_ATTR_STAR_MATCHED; 816 } 817 } 818 } 819 820 /** {@inheritDoc} */ 821 @Override 822 public void setEvalOpAttributes(int v) { 823 if(rightsMask == ACI_READ) { 824 if(v == ACI_FOUND_OP_ATTR_RULE) { 825 evalAllAttributes |= ACI_FOUND_OP_ATTR_RULE; 826 evalAllAttributes &= ~ACI_OP_ATTR_PLUS_MATCHED; 827 } 828 else 829 { 830 evalAllAttributes |= ACI_OP_ATTR_PLUS_MATCHED; 831 } 832 } 833 } 834 835 /** {@inheritDoc} */ 836 @Override 837 public boolean hasEvalUserAttributes() { 838 return hasAttribute(ACI_FOUND_USER_ATTR_RULE); 839 } 840 841 /** {@inheritDoc} */ 842 @Override 843 public boolean hasEvalOpAttributes() { 844 return hasAttribute(ACI_FOUND_OP_ATTR_RULE); 845 } 846 847 /** 848 * Return true if the evaluating ACI contained a targetattr all 849 * user attributes rule match. 850 * 851 * @return True if the above condition was seen. 852 */ 853 public boolean hasAllUserAttributes() { 854 return hasAttribute(ACI_USER_ATTR_STAR_MATCHED); 855 } 856 857 /** 858 * Return true if the evaluating ACI contained a targetattr all 859 * operational attributes rule match. 860 * 861 * @return True if the above condition was seen. 862 */ 863 public boolean hasAllOpAttributes() { 864 return hasAttribute(ACI_OP_ATTR_PLUS_MATCHED); 865 } 866 867 private boolean hasAttribute(int aciAttribute) 868 { 869 return (evalAllAttributes & aciAttribute) == aciAttribute; 870 } 871 872 /** {@inheritDoc} */ 873 @Override 874 public void clearEvalAttributes(int v) { 875 if(v == 0) 876 { 877 evalAllAttributes=0; 878 } 879 else 880 { 881 evalAllAttributes &= ~v; 882 } 883 } 884 885 /** {@inheritDoc} */ 886 @Override 887 public int getCurrentSSF() { 888 return clientConnection.getSSF(); 889 } 890 891 /** {@inheritDoc} */ 892 @Override 893 public String toString() 894 { 895 final StringBuilder sb = new StringBuilder(); 896 if (attributeType != null) 897 { 898 appendSeparatorIfNeeded(sb); 899 sb.append("attributeType: ").append(attributeType.getNameOrOID()); 900 if (attributeValue != null) 901 { 902 sb.append(":").append(attributeValue); 903 } 904 } 905 appendSeparatorIfNeeded(sb); 906 sb.append(size(allowList)).append(" allow ACIs"); 907 appendSeparatorIfNeeded(sb); 908 sb.append(size(denyList)).append(" deny ACIs"); 909 if (evalReason != null) 910 { 911 appendSeparatorIfNeeded(sb); 912 sb.append("evaluationResult: ").append(evalReason); 913 if (decidingAci != null) 914 { 915 sb.append(",").append(decidingAci); 916 } 917 } 918 return sb.toString(); 919 } 920 921 private void appendSeparatorIfNeeded(StringBuilder sb) 922 { 923 if (sb.length() > 0) 924 { 925 sb.append(", "); 926 } 927 } 928 929 private int size(Collection<?> col) 930 { 931 if (col != null) 932 { 933 return col.size(); 934 } 935 return 0; 936 } 937}