AciEffectiveRights.java revision 88f16d892d54fd8c3e190cc1f6363638b11ae1a3
/*
* 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
* 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 2011-2015 ForgeRock AS
*/
/**
* This class implements the dseecompat geteffectiverights evaluation.
*/
public class AciEffectiveRights {
/**
* Value used when a aclRights attribute was seen in the search operation
* attribute set.
*/
private static final int ACL_RIGHTS = 0x001;
/**
* Value used when a aclRightsInfo attribute was seen in the search operation
* attribute set.
*/
private static final int ACL_RIGHTS_INFO = 0x002;
/**
* Value used when an ACI has a targattrfilters keyword match and the result
* of the access check was a deny.
*/
private static final int ACL_TARGATTR_DENY_MATCH = 0x004;
/**
* Value used when an ACI has a targattrfilters keyword match and the result
* of the access check was an allow.
*/
private static final int ACL_TARGATTR_ALLOW_MATCH = 0x008;
/**
* String used to build attribute type name when an aclRights result needs to
* be added to the return entry.
*/
/**
* String used to build attribute type name when an AclRightsInfo result needs
* to be added to the return entry.
*/
/**
* String used to build attribute type name when an entryLevel rights
* attribute type name needs to be added to the return entry.
*/
/**
* String used to build attribute type name when an attributeLevel rights
* attribute type name needs to be added to the return entry.
*/
/**
* The string that is used as the attribute type name when an aclRights
* entryLevel evaluation needs to be added to the return entry.
*/
private static final String aclRightsEntryLevelStr=
/**
* The string that is used as the attribute type name when an aclRights
* attribute level evaluation needs to be added to the return entry. This
* string has the attribute type name used in the evaluation appended to it to
* form the final attribute type name.
*/
private static final String aclRightsAttributeLevelStr=
/**
* The string used to build attribute type name when an attribute level
* aclRightsInfo attribute needs to be added to the return entry. This string
* has the attribute type name used in the evaluation appended to it to form
* the final attribute type name.
*/
private static final String aclRightsInfoAttrLogsStr =
aclRightsInfoAttrStr + ";logs;attributeLevel";
/**
* The string used to build attribute type name when an entryLevel
* aclRightsInfo attribute needs to be added to the return entry.
*/
private static final String aclRightsInfoEntryLogsStr =
aclRightsInfoAttrStr + ";logs;entryLevel";
/**
* Attribute type used in access evaluation to see if the geteffectiverights
* related to the "aclRights" attribute can be performed.
*/
private static AttributeType aclRights;
/**
* Attribute type used in access evaluation to see if the geteffectiverights
* related to the "aclRightsInfo" attribute can be performed.
*/
private static AttributeType aclRightsInfo;
/** Attribute type used in the geteffectiverights selfwrite evaluation. */
private static AttributeType dnAttributeType;
/**The distinguishedName string. */
/**
* String used to fill in the summary status field when access was allowed.
*/
/**
* String used to fill in the summary status field when access was not
* allowed.
*/
/** Evaluated as anonymous user. Used to fill in summary field. */
/** Format used to build the summary string. */
private static String summaryFormatStr =
" (not proxied) ( reason: %s %s)";
/**
* Strings below represent access denied or allowed evaluation reasons. Used
* to fill in the summary status field. Access evaluated an allow ACI.
*/
/** Access evaluated a deny ACI. */
/** Access evaluated deny because there were no allow ACIs. */
/** Access evaluated deny because no allow or deny ACIs evaluated. */
/** Access evaluated allow because the clientDN has bypass-acl privileges. */
//TODO add support for the modify-acl privilege?
/**
* Attempts to add the geteffectiverights asked for in the search to the entry
* being returned. The two geteffectiverights attributes that can be requested
* are: aclRights and aclRightsInfo. The aclRightsInfo attribute will return
* a summary string describing in human readable form, a summary of each
* requested evaluation result. Here is a sample aclRightsInfo summary:
*
* acl_summary(main): access_not_allowed(proxy) on
* (uid=superuser,ou=acis,dc=example,dc=com) (not proxied)
* (reason: no acis matched the resource )
*
* The aclRights attribute will return a simple
* string with the following format:
*
* add:0,delete:0,read:1,write:?,proxy:0
*
* A 0 represents access denied, 1 access allowed and ? that evaluation
* depends on a value of an attribute (targattrfilter keyword present in ACI).
*
* There are two levels of rights information:
*
* 1. entryLevel - entry level rights information
* 2. attributeLevel - attribute level rights information
*
* The attribute type names are built up using subtypes:
*
* aclRights;entryLevel - aclRights entry level presentation
* aclRightsInfo;log;entryLevel;{right} - aclRightsInfo entry level
* presentation for each type of right (proxy, read, write, add,
* delete).
* aclRights;attributeLevel;{attributeType name} - aclRights attribute
* level presentation for each attribute type requested.
* aclRights;attributeLevel;logs;{right};{attributeType name}
* - aclRightsInfo attribute level presentation for each attribute
* type requested.
*
* @param handler The ACI handler to use in the evaluation.
* @param searchAttributes The attributes requested in the search.
* @param container The LDAP operation container to use in the evaluations.
* @param e The entry to add the rights attributes to.
* @param skipCheck True if ACI evaluation was skipped because bypass-acl
* privilege was found.
*/
boolean skipCheck)
{
{
.toLowerCase());
}
if (aclRightsInfo == null)
{
.toLowerCase());
}
if (dnAttributeType == null)
{
}
// Check if the attributes aclRights and aclRightsInfo were requested and
// add attributes less those two attributes to a new list of attribute
// types.
for (String a : searchAttributes)
{
if (aclRightsAttrStr.equalsIgnoreCase(a))
{
attrMask |= ACL_RIGHTS;
}
else if (aclRightsInfoAttrStr.equalsIgnoreCase(a))
{
}
else
{
// Check for shorthands for user attributes "*" or operational "+".
if ("*".equals(a))
{
// Add objectclass.
}
else if ("+".equals(a))
{
}
else
{
.toLowerCase());
}
}
}
// If the special geteffectiverights attributes were not found or
// the user does not have both bypass-acl privs and is not allowed to
// perform rights evalation -- return the entry unchanged.
{
return;
}
// From here on out, geteffectiverights evaluation is being performed and
// the container will be manipulated. First set the flag that
// geteffectiverights evaluation's underway and to use the authZid for
// authorizationDN (they might be the same).
container.useAuthzid(true);
// If no attributes were requested return only entryLevel rights, else
// return attributeLevel rights and entryLevel rights. Always try and
// return the specific attribute rights if they exist.
if (!nonRightsAttrs.isEmpty())
{
skipCheck, false);
}
.getSpecificAttributes(), skipCheck, true);
}
/**
* Perform the attributeLevel rights evaluation on a list of specified
* attribute types. Each attribute has an access check done for the following
* rights: search, read, compare, add, delete, proxy, selfwrite_add,
* selfwrite_delete and write. The special rights, selfwrite_add and
* selfwrite_delete, use the authZid as the attribute value to evaluate
* against the attribute type being evaluated. The selfwrite_add performs the
* access check using the ACI_WRITE_ADD right and selfwrite_delete uses
* ACI_WRITE_ADD right. The write right is made complicated by the
* targattrfilters keyword, which might depend on an unknown value of an
* attribute type. For this case a dummy attribute value is used to try and
* determine if a "?" needs to be placed in the rights string. The special
* flag ACI_SKIP_PROXY_CHECK is always set, so that proxy evaluation is
* bypassed in the Aci Handler's accessAllowed method.
*
* @param container
* The LDAP operation container to use in the evaluations.
* @param handler
* The Aci Handler to use in the access evaluations.
* @param mask
* Mask specifying what rights attribute processing to perform
* (aclRights or aclRightsInfo or both).
* @param retEntry
* The entry to return.
* @param attrList
* The list of attribute types to iterate over.
* @param skipCheck
* True if ACI evaluation was skipped because bypass-acl privilege
* was found.
* @param specificAttr
* True if this evaluation is result of specific attributes sent in
* the request.
*/
private static void addAttributeLevelRights(
boolean skipCheck, boolean specificAttr)
{
// The attribute list might be null.
for(AttributeType a : attrList) {
//Perform search check and append results.
//Perform read check and append results.
//Perform compare and append results.
//Write right is more complicated. Create a dummy value and set that as
//the attribute's value. Call the special writeRightsString method, rather
//than rightsString.
//Perform both selfwrite_add and selfwrite_delete and append results.
if(!specificAttr)
{
}
"selfwrite_add"));
"selfwrite_delete"));
//It is possible that only the aclRightsInfo attribute type was requested.
//Only add the aclRights information if the aclRights attribute type was
//seen.
.toString());
//It is possible that the user might have specified the same attributes
//in both the search and the specific attribute part of the control.
//Only try to add the attribute type if it already hasn't been added.
}
}
}
/**
* Perform the attributeLevel write rights evaluation. The issue here is that
* an ACI could contain a targattrfilters keyword that matches the attribute
* being evaluated. There is no way of knowing if the filter part of the
* targattrfilter would be successful or not. So if the ACI that allowed
* access, has an targattrfilter keyword, a "?" is used as the result of the
* write (depends on attribute value). If the allow ACI doesn't contain a
* targattrfilters keyword than a "1" is added. If the ACI denies then a "0"
* is added. If the skipCheck flag is true, then a 1 is used for the write
* access, since the client DN has bypass privs.
*
* @param container
* The LDAP operation container to use in the evaluations.
* @param handler
* The Aci Handler to use in the access evaluations.
* @param skipCheck
* True if ACI evaluation was skipped because bypass-acl privilege
* was found.
* @return A string representing the rights information.
*/
private static String attributeLevelWriteRights(
boolean skipCheck)
{
//If the user has bypass-acl privs and the authzid is equal to the
//authorization dn, create a right string with a '1' and a valid
//summary. If the user has bypass-acl privs and is querying for
//another authzid or they don't have privs -- fall through.
} else {
// Reset everything.
//Reset name.
//If both booleans are true, then access was allowed by ACIs that did
//not contain targattrfilters.
} else {
//If there is an ACI name then an ACI with a targattrfilters allowed,
//access. A '?' is needed because that evaluation really depends on an
//unknown attribute value, not the dummy value. If there is no ACI
//then one of the above access checks failed and a '0' is needed.
} else {
}
}
}
}
/**
* Perform entryLevel rights evaluation. The rights string is added to the
* entry if the aclRights attribute was seen in the search's requested
* attribute set.
*
* @param container
* The LDAP operation container to use in the evaluations.
* @param handler
* The Aci Handler to use in the access evaluations.
* @param mask
* Mask specifying what rights attribute processing to perform
* (aclRights or aclRightsInfo or both).
* @param retEntry
* The entry to return.
* @param skipCheck
* True if ACI evaluation was skipped because bypass-acl privilege
* was found.
*/
boolean skipCheck)
{
//Perform access evaluations for rights: add, delete, read, write, proxy.
//The read right needs the entry with the full set of attributes. This was
//saved in the Aci Handlers maysend method.
//Switch back to the entry from the Aci Handler's filterentry method.
}
}
/**
* Create the rights for aclRights attributeLevel or entryLevel rights
* evaluation. The only right needing special treatment is the read right
* with no current attribute type set in the container. For that case the
* accessAllowedEntry method is used instead of the accessAllowed method.
*
* @param container The LDAP operation container to use in the evaluations.
* @param handler The Aci Handler to use in the access evaluations.
* @param skipCheck True if ACI evaluation was skipped because bypass-acl
* privilege was found.
* @param rightStr String used representation of the right we are evaluating.
* @return A string representing the aclRights for the current right and
*/
private static
//If the user has bypass-acl privs and the authzid is equal to the
//authorization dn, create a right string with a '1' and a valid
//summary. If the user has bypass-acl privs and is querying for
//another authzid or they don't have privs -- fall through.
} else {
boolean ret;
//Check if read right check, if so do accessAllowedEntry.
else
if(ret)
else
}
}
/**
* attribute types.
*
* @param container The LDAP operation container to use in the evaluations.
* @param handler The Aci Handler to use in the access evaluations.
* @param mask Mask specifying what rights attribute processing to perform
* (aclRights or aclRightsInfo or both).
* @return True if access to the geteffectiverights attribute types are
* allowed.
*/
private static
}
}
}
/**
* Add aclRightsInfo attributeLevel information to the entry. This is the
* summary string built from the last access check.
*
* @param container The LDAP operation container to use in the evaluations.
* @param mask Mask specifying what rights attribute processing to perform
* (aclRights or aclRightsInfo or both).
* @param aType The attribute type to use in building the attribute type name.
* @param retEntry The entry to add the rights information to.
* @param rightStr The string representation of the rights evaluated.
*/
private static
//Check if the aclRightsInfo attribute was requested.
//Build the attribute type.
// The attribute type might have already been added, probably
// not but it is possible.
}
}
/**
* Add aclRightsInfo entryLevel rights to the entry to be returned. This is
* the summary string built from the last access check.
*
* @param container The LDAP operation container to use in the evaluations.
* @param mask Mask specifying what rights attribute processing to perform
* (aclRights or aclRightsInfo or both).
* @param retEntry The entry to add the rights information to.
* @param rightStr The string representation of the rights evaluated.
*/
private static
//Check if the aclRightsInfo attribute was requested.
}
}
/**
* Check if the provided mask has a specific rights attr value.
*
* @param mask The mask with the attribute flags.
* @param rightsAttr The rights attr value to check for.
* @return True if the mask contains the rights attr value.
*/
}
/**
* Create the summary string used in the aclRightsInfo log string.
*
* @param evalCtx The evaluation context to gather information from.
* @param evalRet The value returned from the access evaluation.
* @return A summary of the ACI evaluation
*/
{
//Try and determine what reason string to use.
//Only manipulate the evaluation context's targattrfilters ACI name
//if not a selfwrite evaluation and the context's targattrfilter match
//hashtable is not empty.
if(!evalCtx.isTargAttrFilterMatchAciEmpty() &&
//If the allow list was empty then access is '0'.
} else if(evalRet) {
//The evaluation returned true, clear the evaluation context's
//targattrfilters ACI name only if a deny targattrfilters ACI
//was not seen. It could remove the allow.
} else {
//The evaluation returned false. If the reason was an
//explicit deny evaluation by a non-targattrfilters ACI, clear
//the evaluation context's targattrfilters ACI name since targattrfilter
//evaluation is pretty much ignored during geteffectiverights eval.
//Else, it was a non-explicit deny, if there is not a targattrfilters
//ACI that might have granted access the deny stands, else there is
//a targattrfilters ACI that might grant access.
}
}
//Actually build the string.
}
{
return EVALUATED_ALLOW;
return EVALUATED_DENY;
return NO_ALLOWS;
return NO_ALLOWS_MATCHED;
return SKIP_ACI;
return "";
}
{
{
}
{
}
return decideAci;
}
/**
* If the specified ACI is in the targattrfilters hashtable contained in the
* evaluation context, set the evaluation context's targattrfilters match
* variable to either ACL_TARGATTR_DENY_MATCH or ACL_TARGATTR_ALLOW_MATCH
* depending on the value of the variable denyAci.
*
* @param evalCtx The evaluation context to evaluate and save information to.
* @param aci The ACI to match.
* @param denyAci True if the evaluation was a allow, false if the
* evaluation was an deny or the ACI is not in the table.
* @return True if the ACI was found in the hashtable.
*/
public static
return true;
}
return false;
}
/**
* Finalizes static variables on shutdown so that we release the memory
* associated with them (for the unit tests) and get fresh copies if we're
* doing an in-core restart.
*/
public static void finalizeOnShutdown() {
}
}