/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. * Portions Copyright 2012 ForgeRock AS */ package org.opends.server.authorization.dseecompat; import org.opends.messages.Message; import static org.opends.messages.AccessControlMessages.*; import static org.opends.server.authorization.dseecompat.Aci.*; import java.util.HashSet; import java.util.regex.Pattern; import org.opends.server.core.DirectoryServer; import org.opends.server.types.AttributeType; /** * A class representing an ACI's targetattr keyword. */ public class TargetAttr { /* * Enumeration representing the targetattr operator. */ private EnumTargetOperator operator = EnumTargetOperator.EQUALITY; /* * Flags that is set if all user attributes pattern seen "*". */ private boolean allUserAttributes = false ; /* * Flags that is set if all operational attributes pattern seen "+". */ private boolean allOpAttributes = false ; /* * HashSet of the attribute types parsed by the constructor. */ private HashSet<AttributeType> attributes = new HashSet<AttributeType>(); /** * HashSet of the operational attribute types parsed by the constructor. */ private HashSet<AttributeType> opAttributes = new HashSet<AttributeType>(); /* * Regular expression that matches one or more ATTR_NAME's separated by * the "||" token. */ private static final String attrListRegex = ZERO_OR_MORE_WHITESPACE + ATTR_NAME + ZERO_OR_MORE_WHITESPACE + "(" + LOGICAL_OR + ZERO_OR_MORE_WHITESPACE + ATTR_NAME + ZERO_OR_MORE_WHITESPACE + ")*"; /** * Constructor creating a class representing a targetattr keyword of an ACI. * @param operator The operation enumeration of the targetattr * expression (=, !=). * @param attrString A string representing the attributes specified in * the targetattr expression (ie, dn || +). * @throws AciException If the attrs string is invalid. */ private TargetAttr(EnumTargetOperator operator, String attrString) throws AciException { this.operator = operator; if (attrString != null) { if (Pattern.matches(ALL_USER_ATTRS_WILD_CARD, attrString) ) allUserAttributes = true ; else if (Pattern.matches(ALL_OP_ATTRS_WILD_CARD, attrString) ) allOpAttributes = true ; else { if (Pattern.matches(ZERO_OR_MORE_WHITESPACE, attrString)){ allUserAttributes = false; allOpAttributes=false; } else { if (Pattern.matches(attrListRegex, attrString)) { // Remove the spaces in the attr string and // split the list. Pattern separatorPattern = Pattern.compile(LOGICAL_OR); attrString= attrString.replaceAll(ZERO_OR_MORE_WHITESPACE, ""); String[] attributeArray= separatorPattern.split(attrString); //Add each element of array to appropriate HashSet //after conversion to AttributeType. arrayToAttributeTypes(attributeArray, attrString); } else { Message message = WARN_ACI_SYNTAX_INVALID_TARGETATTRKEYWORD_EXPRESSION. get(attrString); throw new AciException(message); } } } } } /** * Converts each element of an array of attribute strings * to attribute types and adds them to either the user attributes HashSet or * the operational attributes HashSet. Also, scan for the shorthand tokens * "*" for all user attributes and "+" for all operational attributes. * * @param attributeArray The array of attribute type strings. * @param attrStr String used in error message if an Aci Exception * is thrown. * @throws AciException If the one of the attribute checks fails. */ private void arrayToAttributeTypes(String[] attributeArray, String attrStr) throws AciException { for (int i=0, n=attributeArray.length; i < n; i++) { String attribute=attributeArray[i].toLowerCase(); if(attribute.equals("*")) { if(!allUserAttributes) allUserAttributes=true; else { Message message = WARN_ACI_TARGETATTR_INVALID_ATTR_TOKEN.get(attrStr); throw new AciException(message); } } else if(attribute.equals("+")) { if(!allOpAttributes) allOpAttributes=true; else { Message message = WARN_ACI_TARGETATTR_INVALID_ATTR_TOKEN.get(attrStr); throw new AciException(message); } } else { AttributeType attributeType; if((attributeType = DirectoryServer.getAttributeType(attribute)) == null) attributeType = DirectoryServer.getDefaultAttributeType(attribute); if(attributeType.isOperational()) opAttributes.add(attributeType); else attributes.add(attributeType); } } } /** * Returns the operator enumeration of the targetattr expression. * @return The operator enumeration. */ public EnumTargetOperator getOperator() { return operator; } /** * This flag is set if the parsing code saw: * targetattr="*" or targetattr != "*". * @return True if all attributes was seen. */ public boolean isAllUserAttributes() { return allUserAttributes; } /** * This flag is set if the parsing code saw: * targetattr="+" or targetattr != "+". * @return True if all attributes was seen. */ public boolean isAllOpAttributes() { return allOpAttributes; } /** * Return array holding each attribute type to be evaluated * in the expression. * @return Array holding each attribute types. */ public HashSet<AttributeType> getAttributes() { return attributes; } /** * Return array holding operational attribute types to be evaluated * in the expression. * @return Array holding attribute types. */ public HashSet<AttributeType> getOpAttributes() { return opAttributes; } /** * Decodes an targetattr expression string into a targetattr class suitable * for evaluation. * @param operator The operator enumeration of the expression. * @param expr The expression string to be decoded. * @return A TargetAttr suitable to evaluate this ACI's targetattrs. * @throws AciException If the expression string is invalid. */ public static TargetAttr decode(EnumTargetOperator operator, String expr) throws AciException { return new TargetAttr(operator, expr); } /** * Performs test to see if the specified attribute type is applicable * to the specified TargetAttr. First a check if the TargetAttr parsing * code saw an expression like: * * (targetattrs="+ || *"), (targetattrs != "* || +") * * where both shorthand tokens where parsed. IF so then the attribute type * matches automatically (or not matches if NOT_EQUALITY). * * If there isn't a match, then the method evalAttrType is called to further * evaluate the attribute type and targetAttr combination. * * * @param a The attribute type to evaluate. * @param targetAttr The ACI's TargetAttr class to evaluate against. * @return The boolean result of the above tests and application * TargetAttr's operator value applied to the test result. */ public static boolean isApplicable(AttributeType a, TargetAttr targetAttr) { boolean ret; if(targetAttr.isAllUserAttributes() && targetAttr.isAllOpAttributes()) { ret = !targetAttr.getOperator().equals(EnumTargetOperator.NOT_EQUALITY); } else ret=evalAttrType(a, targetAttr); return ret; } /** * First check is to see if the attribute type is operational. If so then * a match is true if the allOpAttributes boolean is true or if the * attribute type is found in the operational attributes HashSet. * Both results can be negated if the expression operator is NOT_EQUALITY). * * Second check is similar to above, except the user attributes boolean * and HashSet is examined. * * * @param a The attribute type to evaluate. * @param targetAttr The targetAttr to apply to the attribute type. * @return True if the attribute type is applicable to the targetAttr. */ private static boolean evalAttrType(AttributeType a, TargetAttr targetAttr) { boolean ret=false; if(a.isOperational()) { if(targetAttr.isAllOpAttributes() || targetAttr.opAttributes.contains(a)) ret=true; if(targetAttr.isAllOpAttributes() || !targetAttr.attributes.isEmpty() || !targetAttr.opAttributes.isEmpty()) { if(targetAttr.getOperator(). equals(EnumTargetOperator.NOT_EQUALITY)) ret=!ret; } } else { if(targetAttr.isAllUserAttributes() || targetAttr.attributes.contains(a)) ret=true; if(targetAttr.isAllUserAttributes() || !targetAttr.opAttributes.isEmpty() || !targetAttr.attributes.isEmpty()) { if(targetAttr.getOperator(). equals(EnumTargetOperator.NOT_EQUALITY)) ret=!ret; } } return ret; } }