opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
@@ -110,12 +110,11 @@ /** * Regular expression that graciously matches an attribute type name. Must * begin with an ASCII letter or digit, and contain only ASCII letters, * digit characters, hyphens, semi-colons and underscores. It also allows * the special shorthand characters "*" for all user attributes and "+" for * all operational attributes. * digit characters, hyphens, semi-colons and underscores. * They are case insensitive. */ public static final String ATTR_NAME = "((?i)[a-z\\d]{1}[[a-z]\\d-_.;]*(?-i)|\\*{1}|\\+{1})"; "((?i)[a-z\\d]{1}[[a-z]\\d-_.;]*(?-i))"; /** * Regular expression matching a LDAP URL. @@ -151,16 +150,8 @@ /** * Regular expression the matches "*". */ public static final String ALL_USER_ATTRS_WILD_CARD = ZERO_OR_MORE_WHITESPACE + "\\*" + ZERO_OR_MORE_WHITESPACE; /** * Regular expression the matches "+". */ public static final String ALL_OP_ATTRS_WILD_CARD = ZERO_OR_MORE_WHITESPACE + "\\+" + ZERO_OR_MORE_WHITESPACE; public static final String ALL_ATTRS_WILD_CARD = ZERO_OR_MORE_WHITESPACE + "\\*" + ZERO_OR_MORE_WHITESPACE; /** * ACI_ADD is used to set the container rights for a LDAP add operation. @@ -274,38 +265,15 @@ * evaluation if the flag is ACI_ATTR_STAR_MATCHED (all attributes match) * and the attribute type is not operational. */ public static final int ACI_USER_ATTR_STAR_MATCHED = 0x0008; public static final int ACI_ATTR_STAR_MATCHED = 0x0008; /** * ACI_FOUND_USER_ATTR_RULE is the flag set when the evaluation reason of a * ACI_FOUND_ATTR_RULE is the flag set when the evaluation reason of a * AciHandler.maysend ACI_READ access evaluation was the result of an * ACI targetattr specific user attribute expression * (targetattr="some user attribute type") target match. * ACI targetattr specific attribute expression * (targetattr="some attribute type") target match. */ public static final int ACI_FOUND_USER_ATTR_RULE = 0x0010; /** * ACI_OP_ATTR_PLUS_MATCHED is the flag set when the evaluation reason of a * AciHandler.maysend ACI_READ access evaluation was the result of an * ACI targetattr all operational attributes expression (targetattr="+") * target match. For this flag to be set, there must be only one * ACI matching. * * This flag and ACI_FOUND_OP_ATTR_RULE are used in the * AciHandler.filterEntry.accessAllowedAttrs method to skip access * evaluation if the flag is ACI_OP_ATTR_PLUS_MATCHED (all operational * attributes match) and the attribute type is operational. */ public static final int ACI_OP_ATTR_PLUS_MATCHED = 0x0004; /** * ACI_FOUND_OP_ATTR_RULE is the flag set when the evaluation reason of a * AciHandler.maysend ACI_READ access evaluation was the result of an * ACI targetattr specific operational attribute expression * (targetattr="some operational attribute type") target match. */ public static final int ACI_FOUND_OP_ATTR_RULE = 0x0020; public static final int ACI_FOUND_ATTR_RULE = 0x0010; /** * ACI_NULL is used to set the container rights to all zeros. Used opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -280,20 +280,12 @@ this.authzid=getEffectiveRightsControl.getAuthzDN(); this.specificAttrs=getEffectiveRightsControl.getAttributes(); } //If an ACI evaluated because of an Targetattr="*", then the //If the ACI evaluated because of an Targetattr="*", then the //AciHandler.maySend method signaled this via adding this attachment //string. String allUserAttrs= (String)operation.getAttachment(ALL_USER_ATTRS_MATCHED); if(allUserAttrs != null) evalAllAttributes |= ACI_USER_ATTR_STAR_MATCHED; //If an ACI evaluated because of an Targetattr="+", then the //AciHandler.maySend method signaled this via adding this attachment //string. String allOpAttrs=(String)operation.getAttachment(ALL_OP_ATTRS_MATCHED); if(allOpAttrs != null) evalAllAttributes |= ACI_OP_ATTR_PLUS_MATCHED; String allAttrs=(String)operation.getAttachment(ALL_ATTRS_MATCHED); if(allAttrs != null) evalAllAttributes = ACI_ATTR_STAR_MATCHED; //The AciHandler.maySend method also adds the full attribute version of //the resource entry in this attachment. fullEntry=(Entry)operation.getAttachment(ALL_ATTRS_RESOURCE_ENTRY); @@ -831,74 +823,43 @@ /** * {@inheritDoc} */ public void setEvalUserAttributes(int v) { public void setACIEvalAttributesRule(int v) { if(operation instanceof SearchOperation && (rights == ACI_READ)) { if(v == ACI_FOUND_USER_ATTR_RULE) { evalAllAttributes |= ACI_FOUND_USER_ATTR_RULE; evalAllAttributes &= ~ACI_USER_ATTR_STAR_MATCHED; if(v == ACI_FOUND_ATTR_RULE) { evalAllAttributes |= ACI_FOUND_ATTR_RULE; evalAllAttributes &= ~ACI_ATTR_STAR_MATCHED; } else evalAllAttributes |= ACI_USER_ATTR_STAR_MATCHED; } } /** * {@inheritDoc} */ public void setEvalOpAttributes(int v) { if(operation instanceof SearchOperation && (rights == ACI_READ)) { if(v == ACI_FOUND_OP_ATTR_RULE) { evalAllAttributes |= ACI_FOUND_OP_ATTR_RULE; evalAllAttributes &= ~ACI_OP_ATTR_PLUS_MATCHED; } else evalAllAttributes |= ACI_OP_ATTR_PLUS_MATCHED; evalAllAttributes |= Aci.ACI_ATTR_STAR_MATCHED; } } /** * {@inheritDoc} */ public boolean hasEvalUserAttributes() { return (evalAllAttributes & ACI_FOUND_USER_ATTR_RULE) == ACI_FOUND_USER_ATTR_RULE; public boolean hasACIEvalAttributes() { return (evalAllAttributes & ACI_FOUND_ATTR_RULE) == ACI_FOUND_ATTR_RULE; } /** * Return true if the evaluating ACI either contained a targetattr all * attributes rule matched only. * * @return True if the above condition was seen. **/ public boolean hasACIAllAttributes() { return (evalAllAttributes & ACI_ATTR_STAR_MATCHED) == ACI_ATTR_STAR_MATCHED; } /** * {@inheritDoc} */ public boolean hasEvalOpAttributes() { return (evalAllAttributes & ACI_FOUND_OP_ATTR_RULE) == ACI_FOUND_OP_ATTR_RULE; } /** * Return true if the evaluating ACI contained a targetattr all * user attributes rule match. * * @return True if the above condition was seen. **/ public boolean hasAllUserAttributes() { return (evalAllAttributes & ACI_USER_ATTR_STAR_MATCHED) == ACI_USER_ATTR_STAR_MATCHED; } /** * Return true if the evaluating ACI contained a targetattr all * operational attributes rule match. * * @return True if the above condition was seen. **/ public boolean hasAllOpAttributes() { return (evalAllAttributes & ACI_OP_ATTR_PLUS_MATCHED) == ACI_OP_ATTR_PLUS_MATCHED; } /** * {@inheritDoc} */ public void clearEvalAttributes(int v) { public void clearACIEvalAttributesRule(int v) { if(v == 0) evalAllAttributes=0; else evalAllAttributes &= ~v; } } opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -98,16 +98,10 @@ public static String ALL_ATTRS_RESOURCE_ENTRY = "allAttrsResourceEntry"; /** * String used to indicate that the evaluating ACI had a all user attributes * String used to indicate that the evaluating ACI had a all attributes * targetattr match (targetattr="*"). */ public static String ALL_USER_ATTRS_MATCHED = "allUserAttrsMatched"; /** * String used to indicate that the evaluating ACI had a all operational * attributes targetattr match (targetattr="+"). */ public static String ALL_OP_ATTRS_MATCHED = "allOpAttrsMatched"; public static String ALL_ATTRS_MATCHED = "allAttrsMatched"; /** * This constructor instantiates the ACI handler class that performs the @@ -609,18 +603,17 @@ */ private SearchResultEntry accessAllowedAttrs(AciLDAPOperationContainer container) { Entry e=container.getResourceEntry(); List<AttributeType> typeList=getAllAttrs(e); for(AttributeType attrType : typeList) { if(container.hasAllUserAttributes() && !attrType.isOperational()) continue; if(container.hasAllOpAttributes() && attrType.isOperational()) continue; container.setCurrentAttributeType(attrType); if(!accessAllowed(container)) e.removeAttribute(attrType); Entry e=container.getResourceEntry(); List<AttributeType> typeList=getAllAttrs(e); for(AttributeType attrType : typeList) { if(container.hasACIAllAttributes() && !attrType.isOperational()) continue; container.setCurrentAttributeType(attrType); if(!accessAllowed(container)) { e.removeAttribute(attrType); } return container.getSearchResultEntry(); } return container.getSearchResultEntry(); } /** @@ -923,16 +916,12 @@ ret=false; } if (ret) { operationContainer.clearEvalAttributes(ACI_NULL); operationContainer.clearACIEvalAttributesRule(ACI_NULL); operationContainer.setRights(ACI_READ); ret=accessAllowedEntry(operationContainer); if(ret) { if(!operationContainer.hasEvalUserAttributes()) operation.setAttachment(ALL_USER_ATTRS_MATCHED, ALL_USER_ATTRS_MATCHED); if(!operationContainer.hasEvalOpAttributes()) operation.setAttachment(ALL_OP_ATTRS_MATCHED, ALL_OP_ATTRS_MATCHED); if(!operationContainer.hasACIEvalAttributes()) operation.setAttachment(ALL_ATTRS_MATCHED, ALL_ATTRS_MATCHED); } } } opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
@@ -412,8 +412,21 @@ int rights=targetMatchCtx.getRights(); boolean isFirstAttr=targetMatchCtx.isFirstAttribute(); if((a != null) && (targets.getTargetAttr() != null)) { ret=TargetAttr.isApplicable(a,targets.getTargetAttr()); setEvalAttributes(targetMatchCtx,targets,ret); ret=TargetAttr.isApplicable(a,targets.getTargetAttr()); targetMatchCtx.clearACIEvalAttributesRule(ACI_ATTR_STAR_MATCHED); /* If a explicitly defined targetattr's match rule has not been seen (~ACI_FOUND_ATTR_RULE) and the current attribute type is applicable because of a targetattr all attributes rule match, set a flag to indicate this situation (ACI_ATTR_STAR_MATCHED). Else the attributes is applicable because it is operational or not a targetattr's all attribute match. */ if(ret && targets.getTargetAttr().isAllAttributes() && !targetMatchCtx.hasACIEvalAttributes()) targetMatchCtx.setACIEvalAttributesRule(ACI_ATTR_STAR_MATCHED); else targetMatchCtx.setACIEvalAttributesRule(ACI_FOUND_ATTR_RULE); } else if((a != null) || (targets.getTargetAttr() != null)) { if((aci.hasRights(skipRights)) && (skipRightsHasRights(rights))) @@ -550,46 +563,4 @@ } return ret; } /** * The method is used to try and determine if a targetAttr expression that * is applicable has a '*' (or '+' operational attributes) token or if it * was applicable because of a specific attribute type declared in the * targetattrs expression (i.e., targetattrs=cn). * * * @param ctx The ctx to check against. * @param targets The targets part of the ACI. * @param ret The is true if the ACI has already been evaluated to be * applicable. */ private static void setEvalAttributes(AciTargetMatchContext ctx, AciTargets targets, boolean ret) { ctx.clearEvalAttributes(ACI_USER_ATTR_STAR_MATCHED); ctx.clearEvalAttributes(ACI_OP_ATTR_PLUS_MATCHED); /* If an applicable targetattr's match rule has not been seen (~ACI_FOUND_OP_ATTR_RULE or ~ACI_FOUND_USER_ATTR_RULE) and the current attribute type is applicable because of a targetattr all user (or operational) attributes rule match, set a flag to indicate this situation (ACI_USER_ATTR_STAR_MATCHED or ACI_OP_ATTR_PLUS_MATCHED). This check also catches the following case where the match was by a specific attribute type (either user or operational) and the other attribute type has an all attribute token. For example, the expression is: (targetattrs="cn || +) and the current attribute type is cn. */ if(ret && targets.getTargetAttr().isAllUserAttributes() && !ctx.hasEvalUserAttributes()) ctx.setEvalUserAttributes(ACI_USER_ATTR_STAR_MATCHED); else ctx.setEvalUserAttributes(ACI_FOUND_USER_ATTR_RULE); if(ret && targets.getTargetAttr().isAllOpAttributes() && !ctx.hasEvalOpAttributes()) ctx.setEvalOpAttributes(ACI_OP_ATTR_PLUS_MATCHED); else ctx.setEvalOpAttributes(ACI_FOUND_OP_ATTR_RULE); } } opendj-sdk/opends/src/server/org/opends/server/messages/AciMessages.java
@@ -740,15 +740,22 @@ public static final int MSGID_ACI_NOT_VALID_DN = CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 73; /** * The message ID for the message that will be used if a targetattr * keyword expression contains both operational and user attribute * types. This takes one argument, which is the targetattr expression string. */ public static final int MSGID_ACI_TARGETATTR_INVALID_OP_USER_ATTR = CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 74; /** * The message ID for the message that will be used if a targetattr * keyword expression contains an error when a each token in an targetattr * expression was parsed. This takes one argument, which is the expression * string that caused the error. * keyword expression performs both an inequality operation using * operational attribute types. This takes one argument, which is the * targetattr expression string. */ public static final int MSGID_ACI_TARGETATTR_INVALID_ATTR_TOKEN = CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 74; public static final int MSGID_ACI_TARGATTR_INVALID_OP_ATTR_INEQUALITY = CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 75; /** * The message ID for the message that will be used if a roledn @@ -756,7 +763,7 @@ * This takes one argument, which is the roledn expression string. */ public static final int MSGID_ACI_SYNTAX_ROLEDN_NOT_SUPPORTED = CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 75; CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 76; /** * The message ID for the message that will be used if there are ACI decode @@ -765,7 +772,7 @@ * exception. */ public static final int MSGID_ACI_SERVER_DECODE_FAILED = CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 76; CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 77; /** @@ -774,7 +781,7 @@ * causing the server is being put in lockdown mode. The takes no arguments. */ public static final int MSGID_ACI_ENTER_LOCKDOWN_MODE = CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 77; CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 78; /** @@ -1199,11 +1206,17 @@ "Selfwrite check skipped because an attribute \"%s\" with a " + "distinguished name syntax was not a valid DN"); registerMessage(MSGID_ACI_TARGETATTR_INVALID_ATTR_TOKEN, registerMessage(MSGID_ACI_TARGETATTR_INVALID_OP_USER_ATTR, "The provided Access Control Instruction (ACI) " + "targetattr expression value \"%s\" is invalid because" + " the expression contains invalid or duplicate tokens"); " the expression contains both operational attribute types" + " and user attribute types"); registerMessage(MSGID_ACI_TARGATTR_INVALID_OP_ATTR_INEQUALITY, "The provided Access Control Instruction (ACI) " + "targetattr expression value \"%s\" is invalid because" + " the expression performs an inequality operation using " + "operational attribute types"); registerMessage(MSGID_ACI_SYNTAX_ROLEDN_NOT_SUPPORTED, "The provided Access Control Instruction (ACI) expression " + opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
@@ -44,46 +44,9 @@ private static final String user3="uid=user.3,ou=People,o=test"; public static final String aciFilter = "(aci=*)"; private static final String starAciAttrs = "(targetattr=\"* || aci\")" + "(version 3.0;acl \"read/search all user, aci op\";" + "allow (search, read) " + "userattr=\"l#Austin\";)"; private static final String ocOpAttrs = "(targetattr=\"objectclass || +\")" + "(version 3.0;acl \"read/search all op, oc user\";" + "allow (search, read) " + "userattr=\"l#Austin\";)"; private static final String OpSrchAttrs = "(targetattr=\"sn || uid || +\")" + "(version 3.0;acl \"read/search all op, sn uid user\";" + "allow (search, read) " + "userattr=\"l#Austin\";)"; private static final String allAttrs = "(targetattr=\"* || +\")" + "(version 3.0;acl \"read/search all user and all op lattr\";" + "allow (search, read) " + "userattr=\"l#Austin\";)"; private static final String allOpAttrAci1 = "(targetattr=\"+\")" + "(version 3.0;acl \"read/search all op attr\";" + "allow (search, read) " + "userattr!=\"l#New York\";)"; private static final String notAllOpAttrAci1 = "(targetattr!=\"+\")" + "(version 3.0;acl \"read/search not all op attr\";" + "allow (search, read) " + "userattr!=\"l#New York\";)"; private static final String userAttrAci = "(targetattr=\"*\")" + "(version 3.0;acl \"read/search all userattr\";" + "(version 3.0;acl \"read/search userattr\";" + "allow (search, read) " + "userattr=\"l#Austin\";)"; @@ -201,129 +164,6 @@ deleteAttrFromEntry(user1, "aci"); } /** * Test targetattr shorthand behavior, all attrs both user and operational. * See comments. * * @throws Exception If a test result is unexpected. */ @Test() public void testTargetAttrAllAttr() throws Exception { //Add aci with: (targetattr = "+ || *") String aciLdif=makeAddAciLdif("aci", user1, allAttrs); modEntries(aciLdif, DIR_MGR_DN, PWD); String userResults = LDAPSearchParams(user3, PWD, null, null, null, user1, filter, opAttrList); Assert.assertFalse(userResults.equals("")); HashMap<String, String> attrMap=getAttrMap(userResults); //All should be returned. Assert.assertTrue(attrMap.containsKey("aci")); Assert.assertTrue(attrMap.containsKey("sn")); Assert.assertTrue(attrMap.containsKey("uid")); deleteAttrFromEntry(user1, "aci"); } /** * Test targetattr shorthand behavior, userattr and plus sign (all op attrs). * See comments. * * @throws Exception If a test result is unexpected. */ @Test() public void testTargetAttrOpPlusAttr() throws Exception { //Add aci with: (targetattr = "objectclass|| +") String aciLdif=makeAddAciLdif("aci", user1, ocOpAttrs); modEntries(aciLdif, DIR_MGR_DN, PWD); String userResults = LDAPSearchParams(user3, PWD, null, null, null, user1, filter, opAttrList); Assert.assertFalse(userResults.equals("")); HashMap<String, String> attrMap=getAttrMap(userResults); //Only aci should be returned. Assert.assertTrue(attrMap.containsKey("aci")); Assert.assertFalse(attrMap.containsKey("sn")); Assert.assertFalse(attrMap.containsKey("uid")); deleteAttrFromEntry(user1, "aci"); } /** * Test targetattr shorthand behavior, star (all user attr) or aci attr. * See comments. * * @throws Exception If a test result is unexpected. */ @Test() public void testTargetAttrUserStarAttr() throws Exception { //Add aci with: (targetattr = "*|| aci") String aciLdif=makeAddAciLdif("aci", user1, starAciAttrs); modEntries(aciLdif, DIR_MGR_DN, PWD); String userResults = LDAPSearchParams(user3, PWD, null, null, null, user1, filter, opAttrList); Assert.assertFalse(userResults.equals("")); HashMap<String, String> attrMap=getAttrMap(userResults); //All should be returned. Assert.assertTrue(attrMap.containsKey("aci")); Assert.assertTrue(attrMap.containsKey("sn")); Assert.assertTrue(attrMap.containsKey("uid")); deleteAttrFromEntry(user1, "aci"); } /** * Test targetattr shorthand behavior using '+' in expression and an * operational attribute in the filter. The second test is two ACIs one * with targetattr='+' and the other with targetattr='*'. * * @throws Exception If test result is unexpected. */ @Test() public void testTargetAttrSrchShorthand() throws Exception { //Aci: (targetattrs="sn || uid || +) and search with an //operational attr (aci). String aciLdif=makeAddAciLdif("aci", user1, OpSrchAttrs); modEntries(aciLdif, DIR_MGR_DN, PWD); String userResults = LDAPSearchParams(user3, PWD, null, null, null, user1, aciFilter, opAttrList); Assert.assertFalse(userResults.equals("")); HashMap<String, String> attrMap=getAttrMap(userResults); //All should be returned. Assert.assertTrue(attrMap.containsKey("aci")); Assert.assertTrue(attrMap.containsKey("sn")); Assert.assertTrue(attrMap.containsKey("uid")); deleteAttrFromEntry(user1, "aci"); //Add two ACIs, one with '+' and the other with '*'. String aciLdif1=makeAddAciLdif("aci", user1, allOpAttrAci1, userAttrAci); modEntries(aciLdif1, DIR_MGR_DN, PWD); String userResults1 = LDAPSearchParams(user3, PWD, null, null, null, user1, aciFilter, opAttrList); Assert.assertFalse(userResults1.equals("")); HashMap<String, String> attrMap1=getAttrMap(userResults1); //All should be returned. Assert.assertTrue(attrMap1.containsKey("aci")); Assert.assertTrue(attrMap1.containsKey("sn")); Assert.assertTrue(attrMap1.containsKey("uid")); deleteAttrFromEntry(user1, "aci"); //Add two ACIs, one with '+' and the other with '*'. String aciLdif2=makeAddAciLdif("aci", user1, notAllOpAttrAci1, userAttrAci); modEntries(aciLdif2, DIR_MGR_DN, PWD); String userResults2 = LDAPSearchParams(user3, PWD, null, null, null, user1, filter, opAttrList); Assert.assertFalse(userResults2.equals("")); HashMap<String, String> attrMap2=getAttrMap(userResults2); //Only non-operation should be returned. Assert.assertFalse(attrMap2.containsKey("aci")); Assert.assertTrue(attrMap2.containsKey("sn")); Assert.assertTrue(attrMap2.containsKey("uid")); deleteAttrFromEntry(user1, "aci"); } private void checkAttributeVal(HashMap<String, String> attrMap, String attr, String val) throws Exception {