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