/* * The contents of this file are subject to the terms of the Common Development and * Distribution License (the License). You may not use this file except in compliance with the * License. * * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL * Header, with the fields enclosed by brackets [] replaced by your own identifying * information: "Portions Copyright [year] [name of copyright owner]". * * Copyright 2008 Sun Microsystems, Inc. * Portions Copyright 2011-2016 ForgeRock AS. */ package org.opends.server.authorization.dseecompat; import static org.opends.messages.AccessControlMessages.*; import static org.opends.server.protocols.internal.InternalClientConnection.*; import static org.opends.server.protocols.internal.Requests.*; import java.util.LinkedList; import java.util.List; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.LocalizedIllegalArgumentException; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.DN; import org.forgerock.opendj.ldap.SearchScope; import org.forgerock.opendj.ldap.schema.AttributeType; import org.opends.server.core.DirectoryServer; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.protocols.internal.SearchRequest; import org.opends.server.types.Attribute; import org.opends.server.types.DirectoryException; import org.opends.server.types.Entry; import org.opends.server.types.LDAPURL; import org.opends.server.types.SearchResultEntry; /** * This class implements the userattr bind rule keyword. *
* TODO Evaluate making this class more efficient. *
* This class isn't as efficient as it could be. For example, the {@link #evalVAL(AciEvalContext)}
* method should be able to use cached versions of the attribute type and filter.
* The {@link #evalURL(AciEvalContext)} and {@link #evalDNKeywords(AciEvalContext)}
* methods should also be able to use a cached version of the attribute type.
*/
public class UserAttr implements KeywordBindRule {
/** This enumeration is the various types the userattr can have after the "#" token. */
private enum UserAttrType {
USERDN, GROUPDN, ROLEDN, URL, VALUE;
private static UserAttrType getType(String expr) throws AciException {
if("userdn".equalsIgnoreCase(expr)) {
return UserAttrType.USERDN;
} else if("groupdn".equalsIgnoreCase(expr)) {
return UserAttrType.GROUPDN;
} else if("roledn".equalsIgnoreCase(expr)) {
return UserAttrType.ROLEDN;
} else if("ldapurl".equalsIgnoreCase(expr)) {
return UserAttrType.URL;
}
return UserAttrType.VALUE;
}
}
/**
* Used to create an attribute type that can compare the value below in
* an entry returned from an internal search.
*/
private final String attrStr;
/**
* Used to compare a attribute value returned from a search against this
* value which might have been defined in the ACI userattr rule.
*/
private final String attrVal;
/** Contains the type of the userattr, one of the above enumerations. */
private final UserAttrType userAttrType;
/** An enumeration representing the bind rule type. */
private final EnumBindRuleType type;
/** The class used to hold the parent inheritance information. */
private final ParentInheritance parentInheritance;
/**
* Create an non-USERDN/GROUPDN instance of the userattr keyword class.
* @param attrStr The attribute name in string form. Kept in string form
* until processing.
* @param attrVal The attribute value in string form -- used in the USERDN
* evaluation for the parent hierarchy expression.
* @param userAttrType The userattr type of the rule
* "USERDN, GROUPDN, ...".
* @param type The bind rule type "=, !=".
*/
private UserAttr(String attrStr, String attrVal, UserAttrType userAttrType,
EnumBindRuleType type) {
this.attrStr=attrStr;
this.attrVal=attrVal;
this.userAttrType=userAttrType;
this.type=type;
this.parentInheritance = null;
}
/**
* Create an USERDN or GROUPDN instance of the userattr keyword class.
* @param userAttrType The userattr type of the rule (USERDN or GROUPDN)
* only.
* @param type The bind rule type "=, !=".
* @param parentInheritance The parent inheritance class to use for parent
* inheritance checks if any.
*/
private UserAttr(UserAttrType userAttrType, EnumBindRuleType type,
ParentInheritance parentInheritance) {
this.attrStr = null;
this.attrVal = null;
this.userAttrType=userAttrType;
this.type=type;
this.parentInheritance=parentInheritance;
}
/**
* Decode an string containing the userattr bind rule expression.
* @param expression The expression string.
* @param type The bind rule type.
* @return A class suitable for evaluating a userattr bind rule.
* @throws AciException If the string contains an invalid expression.
*/
public static KeywordBindRule decode(String expression,
EnumBindRuleType type)
throws AciException {
String[] vals=expression.split("#");
if(vals.length != 2) {
LocalizableMessage message =
WARN_ACI_SYNTAX_INVALID_USERATTR_EXPRESSION.get(expression);
throw new AciException(message);
}
UserAttrType userAttrType = UserAttrType.getType(vals[1]);
switch (userAttrType) {
case GROUPDN:
case USERDN: {
ParentInheritance parentInheritance =
new ParentInheritance(vals[0], false);
return new UserAttr (userAttrType, type, parentInheritance);
}
case ROLEDN: {
//The roledn keyword is not supported. Throw an exception with
//a message if it is seen in the expression.
throw new AciException(WARN_ACI_SYNTAX_ROLEDN_NOT_SUPPORTED.get(expression));
}
}
return new UserAttr(vals[0], vals[1], userAttrType, type);
}
/**
* Evaluate the expression using an evaluation context.
* @param evalCtx The evaluation context to use in the evaluation of the
* userattr expression.
* @return An enumeration containing the result of the evaluation.
*/
@Override
public EnumEvalResult evaluate(AciEvalContext evalCtx) {
//The working resource entry might be filtered and not have an
//attribute type that is needed to perform these evaluations. The
//evalCtx has a copy of the non-filtered entry, switch to it for these
//evaluations.
switch(userAttrType) {
case ROLEDN:
case GROUPDN:
case USERDN:
return evalDNKeywords(evalCtx);
case URL:
return evalURL(evalCtx);
default:
return evalVAL(evalCtx);
}
}
/** Evaluate a VALUE userattr type. Look in client entry for an
* attribute value and in the resource entry for the same
* value. If both entries have the same value than return true.
* @param evalCtx The evaluation context to use.
* @return An enumeration containing the result of the
* evaluation.
*/
private EnumEvalResult evalVAL(AciEvalContext evalCtx) {
EnumEvalResult matched= EnumEvalResult.FALSE;
boolean undefined=false;
AttributeType attrType = DirectoryServer.getSchema().getAttributeType(attrStr);
final SearchRequest request = newSearchRequest(evalCtx.getClientDN(), SearchScope.BASE_OBJECT);
InternalSearchOperation op = getRootConnection().processSearch(request);
LinkedList