TargetAttr.java revision a632fbfad0ddbe8b343c6abe8e28dc41e3df9b7e
/*
* 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 legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* 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 legal-notices/CDDLv1_0.txt.
* 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-2015 ForgeRock AS
*/
package org.opends.server.authorization.dseecompat;
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.forgerock.i18n.LocalizableMessage;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.AttributeType;
/**
* A class representing an ACI's targetattr keyword.
*/
class TargetAttr {
/** Enumeration representing the targetattr operator. */
private final EnumTargetOperator operator;
/** Flags that is set if all user attributes pattern seen "*". */
private boolean allUserAttributes;
/** Flags that is set if all operational attributes pattern seen "+". */
private boolean allOpAttributes;
/** Set of the attribute types parsed by the constructor. */
private final HashSet<AttributeType> attributes = new HashSet<>();
/** Set of the operational attribute types parsed by the constructor. */
private final HashSet<AttributeType> opAttributes = new HashSet<>();
/**
* 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 {
throw new AciException(WARN_ACI_SYNTAX_INVALID_TARGETATTRKEYWORD_EXPRESSION.get(attrString));
}
}
}
/**
* 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 (String attr : attributeArray) {
String attribute = attr.toLowerCase();
if(attribute.equals("*")) {
if(!allUserAttributes)
{
allUserAttributes=true;
}
else {
LocalizableMessage message =
WARN_ACI_TARGETATTR_INVALID_ATTR_TOKEN.get(attrStr);
throw new AciException(message);
}
} else if(attribute.equals("+")) {
if(!allOpAttributes)
{
allOpAttributes=true;
}
else {
LocalizableMessage message =
WARN_ACI_TARGETATTR_INVALID_ATTR_TOKEN.get(attrStr);
throw new AciException(message);
}
} else {
AttributeType attrType = DirectoryServer.getAttributeType(attribute, true);
if(attrType.isOperational())
{
opAttributes.add(attrType);
}
else
{
attributes.add(attrType);
}
}
}
}
/**
* 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;
}
/**
* 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.
*/
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.
*/
static boolean isApplicable(AttributeType a, TargetAttr targetAttr) {
if(targetAttr.isAllUserAttributes() && targetAttr.isAllOpAttributes()) {
return !targetAttr.getOperator().equals(EnumTargetOperator.NOT_EQUALITY);
} else {
return evalAttrType(a, targetAttr);
}
}
/**
* 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) {
final EnumTargetOperator op = targetAttr.getOperator();
if(a.isOperational()) {
return evalAttrType(a, targetAttr.isAllOpAttributes(), targetAttr.opAttributes, op);
} else {
return evalAttrType(a, targetAttr.isAllUserAttributes(), targetAttr.attributes, op);
}
}
private static boolean evalAttrType(AttributeType attrType, boolean allAttrs,
HashSet<AttributeType> attrs, EnumTargetOperator op) {
boolean ret = allAttrs || attrs.contains(attrType);
if ((allAttrs || !attrs.isEmpty())
&& op.equals(EnumTargetOperator.NOT_EQUALITY))
{
return !ret;
}
return ret;
}
}