/*
|
* 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.
|
*/
|
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;
|
/** Flags that is set if all operational attributes pattern seen "+". */
|
private boolean allOpAttributes;
|
/** Set of the attribute types parsed by the constructor. */
|
private HashSet<AttributeType> attributes = new HashSet<>();
|
/** Set of the operational attribute types parsed by the constructor. */
|
private 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);
|
if (attrType == null) {
|
attrType = DirectoryServer.getDefaultAttributeType(attribute);
|
}
|
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;
|
}
|
|
/**
|
* 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) {
|
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;
|
}
|
}
|