Add ACI support for Get Effective Rights control. Issue #87.
4 files added
21 files modified
| | |
| | | DESC 'Sun-defined access control information attribute type' |
| | | SYNTAX 1.3.6.1.4.1.26027.1.3.4 USAGE directoryOperation |
| | | X-ORIGIN 'Sun Java System Directory Server' ) |
| | | attributeTypes: ( 1.3.6.1.4.1.42.2.27.9.1.39 NAME 'aclRights' |
| | | DESC 'Sun-defined access control effective rights attribute type' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 |
| | | SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation |
| | | X-ORIGIN 'Sun Java System Directory Server' ) |
| | | attributeTypes: ( 1.3.6.1.4.1.42.2.27.9.1.40 NAME 'aclRightsInfo' |
| | | DESC 'Sun-defined access control effective rights information attribute type' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 |
| | | SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation |
| | | X-ORIGIN 'Sun Java System Directory Server' ) |
| | | attributeTypes: ( 2.16.840.1.113730.3.1.542 NAME 'nsUniqueId' |
| | | DESC 'Sun-defined unique identifier' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 |
| | | SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation |
| | |
| | | |
| | | |
| | | import org.opends.server.core.*; |
| | | import org.opends.server.types.SearchResultEntry; |
| | | import org.opends.server.types.SearchResultReference; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.Operation; |
| | | |
| | | import org.opends.server.types.*; |
| | | |
| | | |
| | | /** |
| | |
| | | */ |
| | | public abstract boolean isProxiedAuthAllowed(Operation operation, |
| | | Entry newAuthorizationEntry); |
| | | |
| | | /** |
| | | * Indicates whether a geteffectiverights control is allowed |
| | | * based on the current operation and the control contents. |
| | | * |
| | | * @param operation |
| | | * The operation with which the geteffectiverights |
| | | * control is associated. This is always a |
| | | * SearchOperation. |
| | | * @param control |
| | | * The control class containing the decoded |
| | | * geteffectiverights control contents. |
| | | * @return <CODE>true</CODE> if the operation should be allowed |
| | | * by the access control configuration, or |
| | | * <CODE>false</CODE> if not. |
| | | */ |
| | | public abstract |
| | | boolean isGetEffectiveRightsAllowed(Operation operation, |
| | | Control control); |
| | | } |
| | | |
| | |
| | | /** |
| | | * ACI_ADD is used to set the container rights for a LDAP add operation. |
| | | */ |
| | | public static final int ACI_ADD = 0x0001; |
| | | public static final int ACI_ADD = 0x0020; |
| | | |
| | | /** |
| | | * ACI_DELETE is used to set the container rights for a LDAP |
| | | * delete operation. |
| | | */ |
| | | public static final int ACI_DELETE = 0x0002; |
| | | public static final int ACI_DELETE = 0x0010; |
| | | |
| | | /** |
| | | * ACI_READ is used to set the container rights for a LDAP |
| | |
| | | * ACI_COMPARE is used to set the container rights for a LDAP |
| | | * compare operation. |
| | | */ |
| | | public static final int ACI_COMPARE = 0x0010; |
| | | public static final int ACI_COMPARE = 0x0001; |
| | | |
| | | /** |
| | | * ACI_SEARCH is used to set the container rights a LDAP search operation. |
| | | */ |
| | | public static final int ACI_SEARCH = 0x0020; |
| | | public static final int ACI_SEARCH = 0x0002; |
| | | |
| | | /** |
| | | * ACI_SELF is used for the SELFWRITE right. |
| | |
| | | public static final int ACI_WRITE_DELETE = 0x400; |
| | | |
| | | /** |
| | | * ACI_SKIP_PROXY_CHECK is used to bypass the proxy access check. |
| | | */ |
| | | public static final int ACI_SKIP_PROXY_CHECK = 0x4000; |
| | | |
| | | /** |
| | | * TARGATTRFILTER_ADD is used to specify that a |
| | | * targattrfilters ADD operation was seen in the ACI. For example, |
| | | * given an ACI with: |
| | |
| | | * @return Returns a decoded ACI representing the string argument. |
| | | * @throws AciException If the parsing of the ACI string fails. |
| | | */ |
| | | |
| | | //MPD remove ConfigException after fixing David's problem |
| | | public static Aci decode (ByteString byteString, DN dn) |
| | | throws AciException { |
| | | String input=byteString.stringValue(); |
| | |
| | | */ |
| | | public static boolean |
| | | isApplicable(Aci aci, AciTargetMatchContext matchCtx) { |
| | | int ctxRights=matchCtx.getRights(); |
| | | //First check if the ACI and context have similar rights. |
| | | if(!aci.hasRights(ctxRights)) { |
| | | //TODO This check might be able to be removed further testing |
| | | // is needed. |
| | | if(!(aci.hasRights(ACI_SEARCH| ACI_READ) && |
| | | matchCtx.hasRights(ACI_SEARCH | ACI_READ))) |
| | | return false; |
| | | } |
| | | return AciTargets.isTargetApplicable(aci, matchCtx) && |
| | | AciTargets.isTargetFilterApplicable(aci, matchCtx) && |
| | | AciTargets.isTargAttrFiltersApplicable(aci, matchCtx) && |
| | |
| | | public static EnumEvalResult evaluate(AciEvalContext evalCtx, Aci aci) { |
| | | return aci.evaluate(evalCtx); |
| | | } |
| | | |
| | | /** |
| | | * Returns the name string of this ACI. |
| | | * @return The name string. |
| | | */ |
| | | public String getName() { |
| | | return this.body.getName(); |
| | | } |
| | | } |
| | |
| | | private static final int VERSION = 1; |
| | | |
| | | /* |
| | | * Regular expression group position for the namr string. |
| | | * Regular expression group position for the name string. |
| | | */ |
| | | private static final int NAME = 2; |
| | | |
| | |
| | | } |
| | | return res; |
| | | } |
| | | |
| | | /** |
| | | * Returns the name string. |
| | | * @return The name string. |
| | | */ |
| | | public String getName() { |
| | | return this.name; |
| | | } |
| | | } |
| | |
| | | import org.opends.server.api.Group; |
| | | import org.opends.server.api.ConnectionSecurityProvider; |
| | | import org.opends.server.core.AddOperation; |
| | | import org.opends.server.core.SearchOperation; |
| | | import org.opends.server.extensions.TLSConnectionSecurityProvider; |
| | | import org.opends.server.types.Operation; |
| | | import java.net.InetAddress; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.HashMap; |
| | | |
| | | import static org.opends.server.authorization.dseecompat.Aci.*; |
| | | import static org.opends.server.authorization.dseecompat.AciHandler.*; |
| | | import org.opends.server.controls.GetEffectiveRights; |
| | | import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS; |
| | | |
| | | /** |
| | | * The AciContainer class contains all of the needed information to perform |
| | |
| | | * The entry being evaluated (resource entry). |
| | | */ |
| | | private Entry resourceEntry; |
| | | private Entry saveResourceEntry; |
| | | |
| | | /* |
| | | * The client connection information. |
| | |
| | | */ |
| | | private boolean seenEntry=false; |
| | | |
| | | /** |
| | | /* |
| | | * True if geteffectiverights evaluation is in progress. |
| | | */ |
| | | private boolean isGetEffectiveRightsEval=false; |
| | | |
| | | /* |
| | | * True if the operation has a geteffectiverights control. |
| | | */ |
| | | private boolean hasGetEffectiveRightsControl=false; |
| | | |
| | | /* |
| | | * The geteffectiverights authzID in DN format. |
| | | */ |
| | | private DN authzid=null; |
| | | |
| | | /* |
| | | * True if the authZid should be used as the client DN, only used in |
| | | * geteffectiverights evaluation. |
| | | */ |
| | | private boolean useAuthzid=false; |
| | | |
| | | /* |
| | | * The list of specific attributes to get rights for, in addition to |
| | | * any attributes requested in the search. |
| | | */ |
| | | private List<AttributeType> specificAttrs=null; |
| | | |
| | | /* |
| | | * The entry with all of its attributes available. Used in |
| | | * geteffectiverights read entry level evaluation. |
| | | */ |
| | | private Entry fullEntry=null; |
| | | |
| | | /* |
| | | * Table of ACIs that have targattrfilter keywords that matched. Used |
| | | * in geteffectiverights attributeLevel write evaluation. |
| | | */ |
| | | private HashMap<Aci,Aci> targAttrFilterAcis=new HashMap<Aci, Aci>(); |
| | | |
| | | /* |
| | | * The name of a ACI that decided an evaluation and contained a |
| | | * targattrfilter keyword. Used in geteffectiverights attributeLevel |
| | | * write evaluation. |
| | | */ |
| | | private String targAttrFiltersAciName=null; |
| | | |
| | | /* |
| | | * Value that is used to store the allow/deny result of a deciding ACI |
| | | * containing a targattrfilter keyword. Used in geteffectiverights |
| | | * attributeLevel write evaluation. |
| | | */ |
| | | private int targAttrMatch=0; |
| | | |
| | | /* |
| | | * The ACI that decided the last evaluation. Used in geteffectiverights |
| | | * loginfo processing. |
| | | */ |
| | | private Aci decidingAci=null; |
| | | |
| | | /* |
| | | * The reason the last evaluation decision was made. Used both |
| | | * in geteffectiverights loginfo processing and attributeLevel write |
| | | * evaluation. |
| | | */ |
| | | private EnumEvalReason evalReason=null; |
| | | |
| | | /* |
| | | * A summary string holding the last evaluation information in textual |
| | | * format. Used in geteffectiverights loginfo processing. |
| | | */ |
| | | private String summaryString=null; |
| | | |
| | | /** |
| | | * This constructor is used by all currently supported LDAP operations. |
| | | * |
| | | * @param operation The Operation object being evaluated and target |
| | | * matching. |
| | | * |
| | | * @param rights The rights array to use in evaluation and target matching. |
| | | * |
| | | * @param entry The current entry being evaluated and target matched. |
| | | */ |
| | | protected AciContainer(Operation operation, int rights, Entry entry) { |
| | |
| | | if(origAuthorizationEntry != null) |
| | | this.proxiedAuthorization=true; |
| | | this.authorizationEntry=operation.getAuthorizationEntry(); |
| | | |
| | | //Only need to process the geteffectiverights control once, -- for a |
| | | //SearchOperation with read right. It is saved in the operation |
| | | //attachment after that. |
| | | if(operation instanceof SearchOperation && (rights == ACI_READ)) { |
| | | GetEffectiveRights getEffectiveRightsControl = |
| | | (GetEffectiveRights) |
| | | operation.getAttachment(OID_GET_EFFECTIVE_RIGHTS); |
| | | if(getEffectiveRightsControl != null) { |
| | | hasGetEffectiveRightsControl=true; |
| | | if(getEffectiveRightsControl.getAuthzDN() == null) |
| | | this.authzid=getClientDN(); |
| | | else |
| | | this.authzid=getEffectiveRightsControl.getAuthzDN(); |
| | | this.specificAttrs=getEffectiveRightsControl.getAttributes(); |
| | | fullEntry=(Entry)operation.getAttachment(ALL_ATTRS_RESOURCE_ENTRY); |
| | | } |
| | | } |
| | | //Reference the current authorization entry, so it can be put back |
| | | //if an access proxy check was performed. |
| | | this.saveAuthorizationEntry=this.authorizationEntry; |
| | | this.saveResourceEntry=this.resourceEntry; |
| | | this.rights = rights; |
| | | } |
| | | |
| | | /** |
| | | * Returns true if an entry has already been processed by an access proxy |
| | | * check. |
| | | * |
| | | * @return True if an entry has already been processed by an access proxy |
| | | * check. |
| | | */ |
| | |
| | | /** |
| | | * Set to true if an entry has already been processsed by an access proxy |
| | | * check. |
| | | * |
| | | * @param val The value to set the seenEntry boolean to. |
| | | */ |
| | | public void setSeenEntry(boolean val) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns true if proxied authorization is being used. |
| | | * @return True if proxied authorization is being used. |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isProxiedAuthorization() { |
| | | return this.proxiedAuthorization; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isGetEffectiveRightsEval() { |
| | | return this.isGetEffectiveRightsEval; |
| | | } |
| | | |
| | | /** |
| | | * The container is going to be used in a geteffectiverights evaluation, set |
| | | * the flag isGetEffectiveRightsEval to true. |
| | | */ |
| | | public void setGetEffectiveRightsEval() { |
| | | this.isGetEffectiveRightsEval=true; |
| | | } |
| | | |
| | | /** |
| | | * Return true if the container is being used in a geteffectiverights |
| | | * evaluation. |
| | | * |
| | | * @return True if the container is being used in a geteffectiverights |
| | | * evaluation. |
| | | */ |
| | | public boolean hasGetEffectiveRightsControl() { |
| | | return this.hasGetEffectiveRightsControl; |
| | | } |
| | | |
| | | /** |
| | | * Use the DN from the geteffectiverights control's authzId as the |
| | | * client DN, rather than the authorization entry's DN. |
| | | * |
| | | * @param v The valued to set the useAuthzid to. |
| | | */ |
| | | public void useAuthzid(boolean v) { |
| | | this.useAuthzid=v; |
| | | } |
| | | |
| | | /** |
| | | * Return the list of additional attributes specified in the |
| | | * geteffectiveritghts control. |
| | | * |
| | | * @return The list of attributes to return rights information about in the |
| | | * entry. |
| | | */ |
| | | public List<AttributeType> getSpecificAttributes() { |
| | | return this.specificAttrs; |
| | | } |
| | | |
| | | /** |
| | | * During the geteffectiverights entrylevel read evaluation, an entry with all |
| | | * of the attributes used in the AciHandler's maysend method evaluation is |
| | | * needed to perform the evaluation over again. This entry was saved |
| | | * in the operation's attachment mechanism when the container was created |
| | | * during the SearchOperation read evaluation. |
| | | * |
| | | * This method is used to replace the current resource entry with that saved |
| | | * entry to perform the entrylevel read evaluation described above and to |
| | | * switch back to the current resource entry when needed. |
| | | * |
| | | * @param val Specifies if the saved entry should be used or not. True if it |
| | | * should be used, false if the original resource entry should be used. |
| | | * |
| | | */ |
| | | public void useFullResourceEntry(boolean val) { |
| | | if(val) |
| | | resourceEntry=fullEntry; |
| | | else |
| | | resourceEntry=saveResourceEntry; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void addTargAttrFiltersMatchAci(Aci aci) { |
| | | this.targAttrFilterAcis.put(aci, aci); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean hasTargAttrFiltersMatchAci(Aci aci) { |
| | | return this.targAttrFilterAcis.containsKey(aci); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isTargAttrFilterMatchAciEmpty() { |
| | | return this.targAttrFilterAcis.isEmpty(); |
| | | } |
| | | |
| | | /** |
| | | * Reset the values used by the geteffectiverights evaluation to |
| | | * original values. The geteffectiverights evaluation uses the same container |
| | | * repeatedly for different rights evaluations (read, write, proxy,...) and |
| | | * this method resets variables that are specific to a single evaluation. |
| | | */ |
| | | public void resetEffectiveRightsParams() { |
| | | this.targAttrFilterAcis.clear(); |
| | | this.decidingAci=null; |
| | | this.evalReason=null; |
| | | this.targAttrFiltersMatch=false; |
| | | this.summaryString=null; |
| | | this.targAttrMatch=0; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void setTargAttrFiltersAciName(String name) { |
| | | this.targAttrFiltersAciName=name; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String getTargAttrFiltersAciName() { |
| | | return this.targAttrFiltersAciName; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void setTargAttrFiltersMatchOp(int flag) { |
| | | this.targAttrMatch |= flag; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean hasTargAttrFiltersMatchOp(int flag) { |
| | | return (this.targAttrMatch & flag) != 0; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void setDecidingAci(Aci aci) { |
| | | this.decidingAci=aci; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String getDecidingAciName() { |
| | | if(this.decidingAci != null) |
| | | return this.decidingAci.getName(); |
| | | else return null; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void setEvalReason(EnumEvalReason reason) { |
| | | this.evalReason=reason; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public EnumEvalReason getEvalReason() { |
| | | return this.evalReason; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void setEvalSummary(String summary) { |
| | | this.summaryString=summary; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String getEvalSummary() { |
| | | return this.summaryString; |
| | | } |
| | | |
| | | /** |
| | | * Returns true if the geteffectiverights control's authZid DN is equal to the |
| | | * authoritzation entry's DN. |
| | | * |
| | | * @return True if the authZid is equal to the authorization entry's DN. |
| | | */ |
| | | public boolean isAuthzidAuthorizationDN() { |
| | | return this.authzid.equals(this.authorizationEntry.getDN()); |
| | | } |
| | | |
| | | /** |
| | | * If the specified value is true, then the original authorization entry, |
| | | * which is the entry before the switch performed by the proxied |
| | | * authorization control processing should be set to the current |
| | |
| | | authorizationEntry=saveAuthorizationEntry; |
| | | } |
| | | |
| | | /** |
| | | * The list of deny ACIs. These are all of the applicable |
| | | * ACIs that have a deny permission. Note that an ACI can |
| | | * be on both allow and deny list if it has multiple |
| | | * permission-bind rule pairs. |
| | | * |
| | | * @param denys The list of deny ACIs. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void setDenyList(LinkedList<Aci> denys) { |
| | | denyList=denys; |
| | | } |
| | | |
| | | /** |
| | | * The list of allow ACIs. These are all of the applicable |
| | | * ACIs that have an allow permission. |
| | | * |
| | | * @param allows The list of allow ACIs. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void setAllowList(LinkedList<Aci> allows) { |
| | | allowList=allows; |
| | | } |
| | | |
| | | /** |
| | | * Return the current attribute type being evaluated. |
| | | * @return Attribute type being evaluated. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public AttributeType getCurrentAttributeType() { |
| | | return attributeType; |
| | | } |
| | | |
| | | /** |
| | | * Return the current attribute type value being evaluated. |
| | | * @return Attribute type value being evaluated. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public AttributeValue getCurrentAttributeValue() { |
| | | return attributeValue; |
| | | } |
| | | |
| | | /** |
| | | * Set the attribute type to be evaluated. |
| | | * @param type The attribute type to evaluate. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void setCurrentAttributeType(AttributeType type) { |
| | | attributeType=type; |
| | | } |
| | | |
| | | /** |
| | | * Set the attribute type value to be evaluated. |
| | | * @param value The attribute type value to evaluate. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void setCurrentAttributeValue(AttributeValue value) { |
| | | attributeValue=value; |
| | | } |
| | | |
| | | /** |
| | | * Check is this the first attribute being evaluated in an entry. |
| | | * @return True if it is the first attribute. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isFirstAttribute() { |
| | | return isFirst; |
| | | } |
| | | |
| | | /** |
| | | * Set if this is the first attribute in the entry. |
| | | * @param val True if this is the first attribute being evaluated in the |
| | | * entry. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void setIsFirstAttribute(boolean val) { |
| | | isFirst=val; |
| | | } |
| | | |
| | | /** |
| | | * Check if an entry test rule was seen during target evaluation. |
| | | * @return True if an entry test rule was seen. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean hasEntryTestRule() { |
| | | return isEntryTestRule; |
| | | } |
| | | |
| | | /** |
| | | * Used to set if an entry test rule was seen during target evaluation. |
| | | * @param val Set to true if an entry test rule was seen. |
| | | */ |
| | | public void setEntryTestRule(boolean val) { |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void setEntryTestRule(boolean val) { |
| | | isEntryTestRule=val; |
| | | } |
| | | |
| | | /** |
| | | * Get the entry being evaluated (known as the resource entry). |
| | | * @return The entry being evaluated. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public Entry getResourceEntry() { |
| | | return resourceEntry; |
| | | } |
| | | |
| | | /** |
| | | * Get the entry that corresponds to the client DN. |
| | | * @return The client entry. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public Entry getClientEntry() { |
| | | return this.authorizationEntry; |
| | | } |
| | | |
| | | /** |
| | | * Get the deny list of ACIs. |
| | | * @return The deny ACI list. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public LinkedList<Aci> getDenyList() { |
| | | return denyList; |
| | | } |
| | | |
| | | /** |
| | | * Get the allow list of ACIs. |
| | | * @return The allow ACI list. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public LinkedList<Aci> getAllowList() { |
| | | return allowList; |
| | | } |
| | | |
| | | /** |
| | | * Check is this is a deny ACI evaluation. |
| | | * @return True if the evaluation is using an ACI from |
| | | * deny list. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isDenyEval() { |
| | | return isDenyEval; |
| | | } |
| | | |
| | | /** |
| | | * Check is this operation bound anonymously. |
| | | * @return True if the authentication is anonymous. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isAnonymousUser() { |
| | | return !clientConnection.getAuthenticationInfo().isAuthenticated(); |
| | | } |
| | | |
| | | /** |
| | | * Set the deny evaluation flag. |
| | | * @param val True if this evaluation is a deny ACI. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void setDenyEval(boolean val) { |
| | | isDenyEval = val; |
| | | } |
| | | |
| | | /** |
| | | * Returns the client authorization DN known as the client DN. |
| | | * @return The client's authorization DN. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public DN getClientDN() { |
| | | return this.authorizationEntry.getDN(); |
| | | if(this.useAuthzid) |
| | | return this.authzid; |
| | | else |
| | | return this.authorizationEntry.getDN(); |
| | | } |
| | | |
| | | /** |
| | | * Get the DN of the entry being evaluated. |
| | | * @return The DN of the entry. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public DN getResourceDN() { |
| | | return resourceEntry.getDN(); |
| | | } |
| | | |
| | | /** |
| | | * Checks if the container's rights has the specified rights. |
| | | * @param rights The rights to check for. |
| | | * @return True if the container's rights has the specified rights. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean hasRights(int rights) { |
| | | return (this.rights & rights) != 0; |
| | | } |
| | | |
| | | /** |
| | | * Return the rights set for this container's LDAP operation. |
| | | * @return The rights set for the container's LDAP operation. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public int getRights() { |
| | | return this.rights; |
| | | } |
| | | |
| | | /** |
| | | * Sets the rights for this container to the specified rights. |
| | | * @param rights The rights to set the container's rights to. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void setRights(int rights) { |
| | | this.rights=rights; |
| | | } |
| | | |
| | | /** |
| | | * Gets the hostname of the remote client. |
| | | * @return Cannonical hostname of remote client. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String getHostName() { |
| | | return clientConnection.getRemoteAddress().getCanonicalHostName(); |
| | | } |
| | | |
| | | /** |
| | | * Gets the remote client's address information. |
| | | * @return Remote client's address. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public InetAddress getRemoteAddress() { |
| | | return clientConnection.getRemoteAddress(); |
| | | } |
| | | |
| | | /** |
| | | * Return true if the current operation is a LDAP add operation. |
| | | * @return True if this is an add operation. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isAddOperation() { |
| | | return isAddOp; |
| | | } |
| | | |
| | | /** |
| | | * Set to true if the ACI had a targattrfilter rule that matched. |
| | | * @param v The value to use. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void setTargAttrFiltersMatch(boolean v) { |
| | | this.targAttrFiltersMatch=v; |
| | | } |
| | | |
| | | /** |
| | | * Return the value of the targAttrFiltersMatch variable. This is set to |
| | | * true if the ACI had a targattrfilter rule that matched. |
| | | * @return True if the ACI had a targattrfilter rule that matched. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean getTargAttrFiltersMatch() { |
| | | return targAttrFiltersMatch; |
| | | } |
| | |
| | | return matched; |
| | | } |
| | | |
| | | /** |
| | | * Convenience method that checks if the the clientDN is a member of the |
| | | * specified group. |
| | | * @param group The group to check membership in. |
| | | * @return True if the clientDN is a member of the specified group. |
| | | */ |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isMemberOf(Group group) { |
| | | boolean ret; |
| | | try { |
| | |
| | | } |
| | | return ret; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String rightToString() { |
| | | if(hasRights(ACI_SEARCH)) |
| | | return "search"; |
| | | else if(hasRights(ACI_COMPARE)) |
| | | return "compare"; |
| | | else if(hasRights(ACI_READ)) |
| | | return "read"; |
| | | else if(hasRights(ACI_DELETE)) |
| | | return "delete"; |
| | | else if(hasRights(ACI_ADD)) |
| | | return "add"; |
| | | else if(hasRights(ACI_WRITE)) |
| | | return "write"; |
| | | else if(hasRights(ACI_PROXY)) |
| | | return "proxy"; |
| | | else if(hasRights(ACI_IMPORT)) |
| | | return "import"; |
| | | else if(hasRights(ACI_EXPORT)) |
| | | return "export"; |
| | | else if(hasRights(ACI_WRITE) && |
| | | hasRights(ACI_SELF)) |
| | | return "selfwrite"; |
| | | return null; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * 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 |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.server.authorization.dseecompat; |
| | | |
| | | import org.opends.server.types.*; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import static org.opends.server.authorization.dseecompat.Aci.*; |
| | | import org.opends.server.protocols.asn1.ASN1OctetString; |
| | | |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | | import java.util.LinkedList; |
| | | |
| | | /** |
| | | * 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. |
| | | private static final String aclRightsAttrStr = "aclRights"; |
| | | |
| | | //String used to build attribute type name when an AclRightsInfo result needs |
| | | //to be added to the return entry. |
| | | private static final String aclRightsInfoAttrStr = "aclRightsInfo"; |
| | | |
| | | //String used to build attribute type name when an entryLevel rights |
| | | //attribute type name needs to be added to the return entry. |
| | | private static final String entryLevelStr = "entryLevel"; |
| | | |
| | | //String used to build attribute type name when an attributeLevel rights |
| | | //attribute type name needs to be added to the return entry. |
| | | private static final String attributeLevelStr = "attributeLevel"; |
| | | |
| | | //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= |
| | | aclRightsAttrStr + ";" + entryLevelStr; |
| | | |
| | | //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= |
| | | aclRightsAttrStr + ";" + attributeLevelStr; |
| | | |
| | | //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 = null; |
| | | |
| | | //Attribute type used in access evaluation to see if the geteffectiverights |
| | | //related to the "aclRightsInfo" attribute can be performed. |
| | | private static AttributeType aclRightsInfo = null; |
| | | |
| | | //String used to fill in the summary status field when access was allowed. |
| | | private static String ALLOWED="access allowed"; |
| | | |
| | | //String used to fill in the summary status field when access was not allowed. |
| | | private static String NOT_ALLOWED="access not allowed"; |
| | | |
| | | //Evaluated as anonymous user. Used to fill in summary field. |
| | | private static String anonymous="anonymous"; |
| | | |
| | | //Format used to build the summary string. |
| | | private static String summaryFormatStr = |
| | | "acl_summary(%s): %s(%s) on entry/attr(%s, %s) to (%s)" + |
| | | " (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. |
| | | private static String EVALUATED_ALLOW="evaluated allow"; |
| | | |
| | | //Access evaluated a deny ACI. |
| | | private static String EVALUATED_DENY="evaluated deny"; |
| | | |
| | | //Access evaluated deny because there were no allow ACIs. |
| | | private static String NO_ALLOWS="no acis matched the resource"; |
| | | |
| | | //Access evaluated deny because no allow or deny ACIs evaluated. |
| | | private static String NO_ALLOWS_MATCHED="no acis matched the subject"; |
| | | |
| | | //Access evaluated allow because the clientDN has bypass-acl privileges. |
| | | private static String SKIP_ACI="user has bypass-acl privileges"; |
| | | |
| | | //TODO add support for the modify-acl privilige? |
| | | |
| | | /** |
| | | * 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 |
| | | * entry/attr(uid=proxieduser,ou=acis,dc=example,dc=com, NULL) to |
| | | * (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. |
| | | * @return A SearchResultEntry with geteffectiverights information possibly |
| | | * added to it. |
| | | */ |
| | | public static SearchResultEntry |
| | | addRightsToEntry(AciHandler handler, LinkedHashSet<String> searchAttributes, |
| | | AciLDAPOperationContainer container,SearchResultEntry e, |
| | | boolean skipCheck) { |
| | | List<AttributeType> nonRightsAttrs = new LinkedList<AttributeType>(); |
| | | int attrMask=ACI_NULL; |
| | | if(aclRights == null) |
| | | aclRights = |
| | | DirectoryServer.getAttributeType(aclRightsAttrStr.toLowerCase()); |
| | | if(aclRightsInfo == null) |
| | | aclRightsInfo = |
| | | DirectoryServer.getAttributeType(aclRightsInfoAttrStr.toLowerCase()); |
| | | //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(a.equalsIgnoreCase(aclRightsAttrStr)) |
| | | attrMask |= ACL_RIGHTS; |
| | | else if(a.equalsIgnoreCase(aclRightsInfoAttrStr)) |
| | | attrMask |= ACL_RIGHTS_INFO; |
| | | else { |
| | | AttributeType attrType; |
| | | if((attrType = DirectoryServer.getAttributeType(a)) == null) |
| | | attrType = DirectoryServer.getDefaultAttributeType(a); |
| | | nonRightsAttrs.add(attrType); |
| | | } |
| | | } |
| | | //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. |
| | | if(attrMask == ACI_NULL || |
| | | (!skipCheck && !rightsAccessAllowed(container,handler,attrMask))) |
| | | return e; |
| | | //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.setGetEffectiveRightsEval(); |
| | | 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()) { |
| | | e=addAttributeLevelRights(container,handler,attrMask,e, |
| | | container.getSpecificAttributes(), skipCheck); |
| | | e=addEntryLevelRights(container,handler,attrMask,e, skipCheck); |
| | | } else { |
| | | e=addAttributeLevelRights(container,handler,attrMask,e, |
| | | nonRightsAttrs,skipCheck); |
| | | e=addAttributeLevelRights(container,handler,attrMask,e, |
| | | container.getSpecificAttributes(), skipCheck); |
| | | e=addEntryLevelRights(container,handler,attrMask,e,skipCheck); |
| | | } |
| | | return e; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 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 specifing 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. |
| | | * @return A SearchResultEntry with geteffectiverights attribute level |
| | | * information added to it. |
| | | */ |
| | | private static |
| | | SearchResultEntry addAttributeLevelRights(AciLDAPOperationContainer container, |
| | | AciHandler handler, int mask, |
| | | SearchResultEntry retEntry, |
| | | List<AttributeType> attrList, |
| | | boolean skipCheck) { |
| | | |
| | | //The attribute list might be null. |
| | | if(attrList == null) |
| | | return retEntry; |
| | | for(AttributeType a : attrList) { |
| | | StringBuilder evalInfo=new StringBuilder(); |
| | | container.setCurrentAttributeType(a); |
| | | container.setCurrentAttributeValue(null); |
| | | //Perform search check and append results. |
| | | container.setRights(ACI_SEARCH | ACI_SKIP_PROXY_CHECK); |
| | | evalInfo.append(rightsString(container, handler, skipCheck, "search")); |
| | | addAttrLevelRightsInfo(container, mask, a, retEntry, "search"); |
| | | evalInfo.append(','); |
| | | //Perform read check and append results. |
| | | container.setRights(ACI_READ | ACI_SKIP_PROXY_CHECK); |
| | | evalInfo.append(rightsString(container, handler, skipCheck, "read")); |
| | | addAttrLevelRightsInfo(container, mask, a, retEntry, "read"); |
| | | evalInfo.append(','); |
| | | //Perform compare and append results. |
| | | container.setRights(ACI_COMPARE | ACI_SKIP_PROXY_CHECK); |
| | | evalInfo.append(rightsString(container, handler, skipCheck, "compare")); |
| | | addAttrLevelRightsInfo(container, mask, a, retEntry, "compare"); |
| | | evalInfo.append(','); |
| | | //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. |
| | | AttributeValue val=new AttributeValue(a, "dum###Val"); |
| | | container.setCurrentAttributeValue(val); |
| | | evalInfo.append(attributeLevelWriteRights(container, handler, skipCheck)); |
| | | addAttrLevelRightsInfo(container, mask, a, retEntry, "write"); |
| | | evalInfo.append(','); |
| | | //Perform both selfwrite_add and selfwrite_delete and append results. |
| | | ByteString clientDNStr= |
| | | new ASN1OctetString(container.getClientDN().toString()); |
| | | AttributeValue val1=new AttributeValue(a, clientDNStr); |
| | | container.setCurrentAttributeValue(val1); |
| | | container.setRights(ACI_WRITE_ADD | ACI_SKIP_PROXY_CHECK); |
| | | evalInfo.append(rightsString(container, handler, skipCheck, |
| | | "selfwrite_add")); |
| | | addAttrLevelRightsInfo(container, mask, a, retEntry, "selfwrite_add"); |
| | | evalInfo.append(','); |
| | | container.setRights(ACI_WRITE_DELETE | ACI_SKIP_PROXY_CHECK); |
| | | evalInfo.append(rightsString(container, handler, skipCheck, |
| | | "selfwrite_delete")); |
| | | addAttrLevelRightsInfo(container, mask, a, retEntry, "selfwrite_delete"); |
| | | evalInfo.append(','); |
| | | container.setCurrentAttributeValue(null); |
| | | container.setRights(ACI_PROXY | ACI_SKIP_PROXY_CHECK); |
| | | evalInfo.append(rightsString(container, handler, skipCheck, "proxy")); |
| | | addAttrLevelRightsInfo(container, mask, a, retEntry, "proxy"); |
| | | //It is possible that only the aclRightsInfo attribute type was requested. |
| | | //Only add the aclRights information if the aclRights attribute type was |
| | | //seen. |
| | | if(hasAttrMask(mask, ACL_RIGHTS)) { |
| | | String typeStr=aclRightsAttributeLevelStr + ";" + |
| | | a.getNormalizedPrimaryName(); |
| | | AttributeType attributeType= |
| | | DirectoryServer.getDefaultAttributeType(typeStr); |
| | | LinkedHashSet<AttributeValue> vals = |
| | | new LinkedHashSet<AttributeValue>(); |
| | | vals.add(new AttributeValue(attributeType, evalInfo.toString())); |
| | | Attribute attr = |
| | | new Attribute(attributeType, typeStr, vals); |
| | | //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. |
| | | if(!retEntry.hasAttribute(attributeType)) |
| | | retEntry.addAttribute(attr,null); |
| | | } |
| | | } |
| | | container.setCurrentAttributeValue(null); |
| | | container.setCurrentAttributeType(null); |
| | | return retEntry; |
| | | } |
| | | |
| | | /** |
| | | * 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(AciLDAPOperationContainer container, |
| | | AciHandler handler, boolean skipCheck){ |
| | | boolean addRet=false, delRet=false; |
| | | StringBuilder resString=new StringBuilder(); |
| | | //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. |
| | | if(skipCheck && container.isAuthzidAuthorizationDN()) { |
| | | resString.append("write").append(":1"); |
| | | container.setEvalReason(EnumEvalReason.SKIP_ACI); |
| | | container.setDecidingAci(null); |
| | | createSummary(container, true, "main"); |
| | | } else { |
| | | //Reset everything. |
| | | container.resetEffectiveRightsParams(); |
| | | //Reset name. |
| | | container.setTargAttrFiltersAciName(null); |
| | | container.setRights(ACI_WRITE_ADD | ACI_SKIP_PROXY_CHECK); |
| | | if(handler.accessAllowed(container)) { |
| | | if(container.getTargAttrFiltersAciName() == null) |
| | | addRet=true; |
| | | } |
| | | container.setRights(ACI_WRITE_DELETE | ACI_SKIP_PROXY_CHECK); |
| | | if(handler.accessAllowed(container)) { |
| | | if(container.getTargAttrFiltersAciName() == null) |
| | | delRet=true; |
| | | } |
| | | //If both booleans are true, then access was allowed by ACIs that did |
| | | //not contain targattrfilters. |
| | | if(addRet && delRet) |
| | | resString.append("write").append(":1"); |
| | | 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. |
| | | if(container.getTargAttrFiltersAciName() != null) { |
| | | resString.append("write").append(":?"); |
| | | } else { |
| | | resString.append("write").append(":0"); |
| | | } |
| | | } |
| | | } |
| | | return resString.toString(); |
| | | } |
| | | |
| | | /** |
| | | * 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 specifing 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. |
| | | * @return A SearchResultEntry with geteffectiverights entryLevel rights |
| | | * information added to it. |
| | | */ |
| | | |
| | | private static SearchResultEntry |
| | | addEntryLevelRights(AciLDAPOperationContainer container, |
| | | AciHandler handler, |
| | | int mask, SearchResultEntry retEntry, |
| | | boolean skipCheck) { |
| | | //Perform access evaluations for rights: add, delete, read, write, proxy. |
| | | StringBuilder evalInfo=new StringBuilder(); |
| | | container.setCurrentAttributeType(null); |
| | | container.setRights(ACI_ADD | ACI_SKIP_PROXY_CHECK); |
| | | evalInfo.append(rightsString(container, handler, skipCheck, "add")); |
| | | addEntryLevelRightsInfo(container, mask, retEntry, "add"); |
| | | evalInfo.append(','); |
| | | container.setCurrentAttributeType(null); |
| | | container.setRights(ACI_DELETE | ACI_SKIP_PROXY_CHECK); |
| | | evalInfo.append(rightsString(container, handler, skipCheck, "delete")); |
| | | addEntryLevelRightsInfo(container, mask, retEntry, "delete"); |
| | | evalInfo.append(','); |
| | | container.setCurrentAttributeType(null); |
| | | //The read right needs the entry with the full set of attributes. This was |
| | | //saved in the Aci Handlers maysend method. |
| | | container.useFullResourceEntry(true); |
| | | container.setRights(ACI_READ | ACI_SKIP_PROXY_CHECK); |
| | | evalInfo.append(rightsString(container, handler, skipCheck, "read")); |
| | | addEntryLevelRightsInfo(container, mask, retEntry, "read"); |
| | | evalInfo.append(','); |
| | | //Switch back to the entry from the Aci Handler's filterentry method. |
| | | container.useFullResourceEntry(false); |
| | | container.setCurrentAttributeType(null); |
| | | container.setRights(ACI_WRITE| ACI_SKIP_PROXY_CHECK); |
| | | evalInfo.append(rightsString(container, handler, skipCheck, "write")); |
| | | addEntryLevelRightsInfo(container, mask, retEntry, "write"); |
| | | evalInfo.append(','); |
| | | container.setCurrentAttributeType(null); |
| | | container.setRights(ACI_PROXY| ACI_SKIP_PROXY_CHECK); |
| | | evalInfo.append(rightsString(container, handler, skipCheck, "proxy")); |
| | | addEntryLevelRightsInfo(container, mask, retEntry, "proxy"); |
| | | if(hasAttrMask(mask, ACL_RIGHTS)) { |
| | | AttributeType attributeType= |
| | | DirectoryServer.getDefaultAttributeType(aclRightsEntryLevelStr); |
| | | LinkedHashSet<AttributeValue> vals = new LinkedHashSet<AttributeValue>(); |
| | | vals.add(new AttributeValue(attributeType, evalInfo.toString())); |
| | | Attribute attr = |
| | | new Attribute(attributeType, aclRightsEntryLevelStr, vals); |
| | | retEntry.addAttribute(attr,null); |
| | | } |
| | | return retEntry; |
| | | } |
| | | |
| | | /** |
| | | * 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 |
| | | * attribute type/value combinations. |
| | | */ |
| | | private static |
| | | String rightsString(AciLDAPOperationContainer container, |
| | | AciHandler handler, |
| | | boolean skipCheck, String rightStr){ |
| | | StringBuilder resString=new StringBuilder(); |
| | | container.resetEffectiveRightsParams(); |
| | | //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. |
| | | if(skipCheck && container.isAuthzidAuthorizationDN()) { |
| | | resString.append(rightStr).append(":1"); |
| | | container.setEvalReason(EnumEvalReason.SKIP_ACI); |
| | | container.setDecidingAci(null); |
| | | createSummary(container, true, "main"); |
| | | } else { |
| | | boolean ret; |
| | | //Check if read right check, if so do accessAllowedEntry. |
| | | if(container.hasRights(ACI_READ) && |
| | | container.getCurrentAttributeType() == null) |
| | | ret=handler.accessAllowedEntry(container); |
| | | else |
| | | ret=handler.accessAllowed(container); |
| | | if(ret) |
| | | resString.append(rightStr).append(":1"); |
| | | else |
| | | resString.append(rightStr).append(":0"); |
| | | } |
| | | return resString.toString(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Check that access is allowed on the aclRights and/or aclRightsInfo |
| | | * 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 specifing what rights attribute processing to perform |
| | | * (aclRights or aclRightsInfo or both). |
| | | * @return True if access to the geteffectiverights attribute types are |
| | | * allowed. |
| | | */ |
| | | private static |
| | | boolean rightsAccessAllowed(AciLDAPOperationContainer container, |
| | | AciHandler handler, int mask) { |
| | | boolean retRight=true, retInfo=true; |
| | | if(hasAttrMask(mask, ACL_RIGHTS)) { |
| | | container.setCurrentAttributeType(aclRights); |
| | | container.setRights(ACI_READ | ACI_SKIP_PROXY_CHECK); |
| | | retRight=handler.accessAllowed(container); |
| | | } |
| | | if(hasAttrMask(mask, ACL_RIGHTS_INFO)) { |
| | | container.setCurrentAttributeType(aclRightsInfo); |
| | | container.setRights(ACI_READ | ACI_SKIP_PROXY_CHECK); |
| | | retInfo=handler.accessAllowed(container); |
| | | } |
| | | return !(!retRight || !retInfo); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 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 specifing 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 |
| | | void addAttrLevelRightsInfo(AciLDAPOperationContainer container, int mask, |
| | | AttributeType aType, SearchResultEntry retEntry, |
| | | String rightStr) { |
| | | |
| | | //Check if the aclRightsInfo attribute was requested. |
| | | if(hasAttrMask(mask,ACL_RIGHTS_INFO)) { |
| | | //Build the attribute type. |
| | | String typeStr= |
| | | aclRightsInfoAttrLogsStr + ";" + rightStr + ";" + |
| | | aType.getPrimaryName(); |
| | | AttributeType attributeType= |
| | | DirectoryServer.getDefaultAttributeType(typeStr); |
| | | LinkedHashSet<AttributeValue> vals = new LinkedHashSet<AttributeValue>(); |
| | | vals.add(new AttributeValue(attributeType, container.getEvalSummary())); |
| | | Attribute attr = |
| | | new Attribute(attributeType, typeStr, vals); |
| | | //The attribute type might have already been added, probably not but it |
| | | //is possible. |
| | | if(!retEntry.hasAttribute(attributeType)) |
| | | retEntry.addAttribute(attr,null); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 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 specifing 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 |
| | | void addEntryLevelRightsInfo(AciLDAPOperationContainer container, int mask, |
| | | SearchResultEntry retEntry, |
| | | String rightStr) { |
| | | |
| | | //Check if the aclRightsInfo attribute was requested. |
| | | if(hasAttrMask(mask,ACL_RIGHTS_INFO)) { |
| | | String typeStr= |
| | | aclRightsInfoEntryLogsStr + ";" + rightStr; |
| | | AttributeType attributeType= |
| | | DirectoryServer.getDefaultAttributeType(typeStr); |
| | | LinkedHashSet<AttributeValue> vals = new LinkedHashSet<AttributeValue>(); |
| | | vals.add(new AttributeValue(attributeType, container.getEvalSummary())); |
| | | Attribute attr = |
| | | new Attribute(attributeType, typeStr, vals); |
| | | retEntry.addAttribute(attr,null); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 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. |
| | | */ |
| | | private static boolean hasAttrMask(int mask, int rightsAttr) { |
| | | return (mask & rightsAttr) != 0; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 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. |
| | | * @param srcStr String that can be used to specify where the summary call's |
| | | * origin is. |
| | | */ |
| | | public static |
| | | void createSummary(AciEvalContext evalCtx, boolean evalRet, String srcStr) { |
| | | String accessStatus=NOT_ALLOWED; |
| | | if(evalRet) |
| | | accessStatus=ALLOWED; |
| | | String accessReason=""; |
| | | StringBuilder decideAci=new StringBuilder(""); |
| | | //Try and determine what reason string to use. |
| | | if(evalCtx.getEvalReason() == EnumEvalReason.EVALUATED_ALLOW_ACI) { |
| | | accessReason=EVALUATED_ALLOW; |
| | | decideAci.append(", deciding_aci: ").append(evalCtx.getDecidingAciName()); |
| | | } else if(evalCtx.getEvalReason() == EnumEvalReason.EVALUATED_DENY_ACI) { |
| | | accessReason=EVALUATED_DENY; |
| | | decideAci.append(", deciding_aci: ").append(evalCtx.getDecidingAciName()); |
| | | } else if(evalCtx.getEvalReason() == EnumEvalReason.NO_ALLOW_ACIS) |
| | | accessReason=NO_ALLOWS; |
| | | else if(evalCtx.getEvalReason() == EnumEvalReason.NO_MATCHED_ALLOWS_ACIS) |
| | | accessReason=NO_ALLOWS_MATCHED; |
| | | else if(evalCtx.getEvalReason() == EnumEvalReason.SKIP_ACI) |
| | | accessReason=SKIP_ACI; |
| | | //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() && |
| | | !evalCtx.hasRights(ACI_SELF)) { |
| | | //If the allow list was empty then access is '0'. |
| | | if(evalCtx.getAllowList().isEmpty()) { |
| | | evalCtx.setTargAttrFiltersAciName(null); |
| | | } 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. |
| | | if(!evalCtx.hasTargAttrFiltersMatchOp(ACL_TARGATTR_DENY_MATCH)) |
| | | evalCtx.setTargAttrFiltersAciName(null); |
| | | } 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. |
| | | if(evalCtx.getEvalReason() == EnumEvalReason.EVALUATED_DENY_ACI) |
| | | evalCtx.setTargAttrFiltersAciName(null); |
| | | else if(!evalCtx.hasTargAttrFiltersMatchOp(ACL_TARGATTR_ALLOW_MATCH)) |
| | | evalCtx.setTargAttrFiltersAciName(null); |
| | | } |
| | | } |
| | | //Actually build the string. |
| | | String user=anonymous; |
| | | if(!evalCtx.getClientDN().isNullDN()) |
| | | user=evalCtx.getClientDN().toString(); |
| | | String right=evalCtx.rightToString(); |
| | | AttributeType aType=evalCtx.getCurrentAttributeType(); |
| | | String attrStr="NULL"; |
| | | if(aType != null) |
| | | attrStr=aType.getPrimaryName(); |
| | | if(evalCtx.getTargAttrFiltersAciName() != null) |
| | | decideAci.append(", access depends on attr value"); |
| | | String summaryStr = String.format(summaryFormatStr, srcStr, accessStatus, |
| | | right,evalCtx.getResourceDN().toString(),attrStr, user, |
| | | accessReason, decideAci.toString()); |
| | | evalCtx.setEvalSummary(summaryStr); |
| | | } |
| | | |
| | | /** |
| | | * 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 |
| | | boolean setTargAttrAci(AciEvalContext evalCtx, Aci aci, boolean denyAci) { |
| | | boolean ret=false; |
| | | if(evalCtx.hasTargAttrFiltersMatchAci(aci)) { |
| | | if(denyAci) |
| | | evalCtx.setTargAttrFiltersMatchOp(ACL_TARGATTR_DENY_MATCH); |
| | | else |
| | | evalCtx.setTargAttrFiltersMatchOp(ACL_TARGATTR_ALLOW_MATCH); |
| | | ret=true; |
| | | } |
| | | return ret; |
| | | } |
| | | } |
| | |
| | | |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.api.Group; |
| | | |
| | | import java.net.InetAddress; |
| | |
| | | * member of the specified group. |
| | | */ |
| | | public boolean isMemberOf(Group group); |
| | | |
| | | /** |
| | | * Returns true if the hashtable of ACIs that matched the targattrfilters |
| | | * keyword evaluation is empty. Used by geteffectiverights evaluation to |
| | | * determine the access value to put in the "write" rights evaluation field. |
| | | * |
| | | * @return True if there were not any ACIs that matched targattrfilters |
| | | * keyword evaluation. |
| | | */ |
| | | public boolean isTargAttrFilterMatchAciEmpty(); |
| | | |
| | | /** |
| | | * The context maintains a hashtable of ACIs that matched the targattrfilters |
| | | * keyword evaluation. The hasTargAttrFiltersMatchAci method returns true if |
| | | * the specified ACI is contained in that hashtable. Used by |
| | | * geteffectiverights evaluation to determine the access value to put in the |
| | | * "write" rights evaluation field. |
| | | * |
| | | * @param aci The ACI that to evaluate if it contains a match during |
| | | * targattrfilters keyword evaluation. |
| | | * |
| | | * @return True if a specified ACI matched targattrfilters evaluation. |
| | | */ |
| | | public boolean hasTargAttrFiltersMatchAci(Aci aci); |
| | | |
| | | /** |
| | | * Return true if an ACI that evaluated to deny or allow has an |
| | | * targattrfilters keyword. Used by geteffectiverights |
| | | * evaluation to determine the access value to put in the "write" rights |
| | | * evaluation field. |
| | | * |
| | | * @param flag The integer value specifying either a deny or allow, but not |
| | | * both. |
| | | * |
| | | * @return True if the ACI that evaluated to |
| | | */ |
| | | public boolean hasTargAttrFiltersMatchOp(int flag); |
| | | |
| | | /** |
| | | * Returns true if the evaluation context is being used in a |
| | | * geteffectiverights evaluation. |
| | | * |
| | | * @return True if the evaluation context is being used in a |
| | | * geteffectiverights evaluation. |
| | | */ |
| | | public boolean isGetEffectiveRightsEval(); |
| | | |
| | | /** |
| | | * Set the name of the ACI that last matched a targattrfilters rule. Used |
| | | * in geteffectiverights targattrfilters "write" rights evaluation. |
| | | * |
| | | * @param name The ACI name string matching the targattrfilters rule. |
| | | */ |
| | | public void setTargAttrFiltersAciName(String name); |
| | | |
| | | /** |
| | | * Set a flag that specifies that a ACI that evaluated to either deny or |
| | | * allow contains a targattrfilters keyword. Used by geteffectiverights |
| | | * evaluation to determine the access value to put in the "write" rights |
| | | * evaluation field. |
| | | * |
| | | * @param flag Either the integer value representing an allow or a deny, |
| | | * but not both. |
| | | */ |
| | | public void setTargAttrFiltersMatchOp(int flag); |
| | | |
| | | /** |
| | | * Set the reason the last access evaluation was evaluated the way it |
| | | * was. Used by geteffectiverights evaluation to eventually build the |
| | | * summary string. |
| | | * |
| | | * @param reason The enumeration representing the reason of the last access |
| | | * evaluation. |
| | | */ |
| | | public void setEvalReason(EnumEvalReason reason); |
| | | |
| | | /** |
| | | * Return the reason the last access evaluation was evaluated the way it |
| | | * was. Used by geteffectiverights evaluation to build the summary string. |
| | | * |
| | | * @return The enumeration representing the reason of the last access |
| | | * evaluation. |
| | | */ |
| | | public EnumEvalReason getEvalReason(); |
| | | |
| | | /** |
| | | * Set the ACI that decided that last access evaluation. Used by |
| | | * geteffectiverights evaluation to the build summary string. |
| | | * |
| | | * @param aci The ACI that decided the last access evaluation. |
| | | */ |
| | | public void setDecidingAci(Aci aci); |
| | | |
| | | /** |
| | | * Check if an evaluation context contains a set of access rights. |
| | | * |
| | | * @param rights The rights mask to check. |
| | | * |
| | | * @return True if the evaluation context contains a access right set. |
| | | */ |
| | | public boolean hasRights(int rights); |
| | | |
| | | /** |
| | | * Return the name of the ACI that decided the last access evaluation. Used |
| | | * by geteffectiverights evaluation to build the summmary string. |
| | | * |
| | | * @return The name of the ACI that decided the last access evaluation. |
| | | */ |
| | | public String getDecidingAciName(); |
| | | |
| | | /** |
| | | * Return true if a evaluation context is being used in proxied authorization |
| | | * evaluation. |
| | | * |
| | | * @return True if evaluation context is being used in proxied authorization |
| | | * evaluation. |
| | | */ |
| | | public boolean isProxiedAuthorization(); |
| | | |
| | | /** |
| | | * Get the current attribute type being evaluated. |
| | | * |
| | | * @return The attribute type currently being evaluated. |
| | | */ |
| | | public AttributeType getCurrentAttributeType(); |
| | | |
| | | /** |
| | | * Set the value of the summary string to the specified string. |
| | | * Used in geteffectiverights evaluation to build summary string. |
| | | * |
| | | * @param summary The string to set the summary string to |
| | | */ |
| | | public void setEvalSummary(String summary); |
| | | |
| | | /** |
| | | * Return the access evaluation summary string. Used by the geteffectiverights |
| | | * evaluation when a aclRightsInfo attribute was specified in a search. |
| | | * |
| | | * @return The string describing the access evaluation. |
| | | */ |
| | | public String getEvalSummary(); |
| | | |
| | | /** |
| | | * Return a string representation of the current right being evaluated. |
| | | * Used in geteffectiverights evaluation to build summary string. |
| | | * |
| | | * @return String representation of the current right being evaluated. |
| | | */ |
| | | public String rightToString(); |
| | | |
| | | /** |
| | | * Return the name of the ACI that last matched a targattrfilters rule. Used |
| | | * in geteffectiverights evaluation. |
| | | * |
| | | * @return The name of the ACI that last matched a targattrfilters rule. |
| | | */ |
| | | public String getTargAttrFiltersAciName(); |
| | | } |
| | |
| | | import org.opends.server.protocols.internal.InternalSearchOperation; |
| | | import org.opends.server.protocols.internal.InternalClientConnection; |
| | | import static org.opends.server.schema.SchemaConstants.*; |
| | | import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS; |
| | | |
| | | import java.util.*; |
| | | import java.util.concurrent.locks.Lock; |
| | |
| | | */ |
| | | public static String ORIG_AUTH_ENTRY="origAuthorizationEntry"; |
| | | |
| | | /** |
| | | * String used to save a resource entry containing all the attributes in |
| | | * the SearchOperation attachment list. This is only used during |
| | | * geteffectiverights read right processing when all of an entry'ss |
| | | * attributes need to examined. |
| | | */ |
| | | public static String ALL_ATTRS_RESOURCE_ENTRY = "allAttrsResourceEntry"; |
| | | |
| | | /** |
| | | * This constructor instantiates the ACI handler class that performs the |
| | | * main processing for the dseecompat ACI package. It does the following |
| | |
| | | */ |
| | | private boolean testApplicableLists(AciEvalContext evalCtx) { |
| | | EnumEvalResult res=EnumEvalResult.FALSE; |
| | | //First check deny lists |
| | | evalCtx.setEvalReason(EnumEvalReason.NO_REASON); |
| | | LinkedList<Aci>denys=evalCtx.getDenyList(); |
| | | LinkedList<Aci>allows=evalCtx.getAllowList(); |
| | | //If allows list is empty and not doing geteffectiverights return |
| | | //false. |
| | | if(allows.isEmpty() && !(evalCtx.isGetEffectiveRightsEval() && |
| | | !evalCtx.hasRights(ACI_SELF) && |
| | | evalCtx.isTargAttrFilterMatchAciEmpty())) { |
| | | evalCtx.setEvalReason(EnumEvalReason.NO_ALLOW_ACIS); |
| | | evalCtx.setDecidingAci(null); |
| | | return false; |
| | | } |
| | | evalCtx.setDenyEval(true); |
| | | for(Aci denyAci : denys) { |
| | | res=Aci.evaluate(evalCtx, denyAci); |
| | | //Failure could be returned if a system limit is hit or |
| | | //search fails |
| | | if((res.equals(EnumEvalResult.FAIL) || |
| | | (res.equals(EnumEvalResult.TRUE)))) { |
| | | return false; |
| | | if(res.equals(EnumEvalResult.FAIL)) { |
| | | evalCtx.setEvalReason(EnumEvalReason.EVALUATED_DENY_ACI); |
| | | evalCtx.setDecidingAci(denyAci); |
| | | return false; |
| | | } else if (res.equals(EnumEvalResult.TRUE)) { |
| | | if(evalCtx.isGetEffectiveRightsEval() && |
| | | !evalCtx.hasRights(ACI_SELF) && |
| | | !evalCtx.isTargAttrFilterMatchAciEmpty()) { |
| | | //Iterate to next only if deny ACI contains a targattrfilters |
| | | //keyword. |
| | | if(AciEffectiveRights.setTargAttrAci(evalCtx, denyAci, true)) |
| | | continue; |
| | | evalCtx.setEvalReason(EnumEvalReason.EVALUATED_DENY_ACI); |
| | | evalCtx.setDecidingAci(denyAci); |
| | | return false; |
| | | } else { |
| | | evalCtx.setEvalReason(EnumEvalReason.EVALUATED_DENY_ACI); |
| | | evalCtx.setDecidingAci(denyAci); |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | //Now check the allows -- flip the deny flag to false first. |
| | | evalCtx.setDenyEval(false); |
| | | LinkedList<Aci>allows=evalCtx.getAllowList(); |
| | | for(Aci allowAci : allows) { |
| | | res=Aci.evaluate(evalCtx, allowAci); |
| | | if(res.equals(EnumEvalResult.TRUE)) { |
| | | break; |
| | | } |
| | | res=Aci.evaluate(evalCtx, allowAci); |
| | | if(res.equals(EnumEvalResult.TRUE)) { |
| | | if(evalCtx.isGetEffectiveRightsEval() && |
| | | !evalCtx.hasRights(ACI_SELF) && |
| | | !evalCtx.isTargAttrFilterMatchAciEmpty()) { |
| | | //Iterate to next only if deny ACI contains a targattrfilters |
| | | //keyword. |
| | | if(AciEffectiveRights.setTargAttrAci(evalCtx, allowAci, false)) |
| | | continue; |
| | | evalCtx.setEvalReason(EnumEvalReason.EVALUATED_ALLOW_ACI); |
| | | evalCtx.setDecidingAci(allowAci); |
| | | return true; |
| | | } else { |
| | | evalCtx.setEvalReason(EnumEvalReason.EVALUATED_ALLOW_ACI); |
| | | evalCtx.setDecidingAci(allowAci); |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | return res.getBoolVal(); |
| | | //Nothing matched fall through. |
| | | evalCtx.setEvalReason(EnumEvalReason.NO_MATCHED_ALLOWS_ACIS); |
| | | evalCtx.setDecidingAci(null); |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | |
| | | allows.add(aci); |
| | | } |
| | | } |
| | | if(targetMatchCtx.getTargAttrFiltersMatch()) |
| | | targetMatchCtx.setTargAttrFiltersMatch(false); |
| | | } |
| | | targetMatchCtx.setAllowList(allows); |
| | | targetMatchCtx.setDenyList(denys); |
| | |
| | | * |
| | | * @return True if access is allowed. |
| | | */ |
| | | private boolean accessAllowed(AciContainer container) |
| | | boolean accessAllowed(AciContainer container) |
| | | { |
| | | DN dn = container.getResourceEntry().getDN(); |
| | | //For ACI_WRITE_ADD and ACI_WRITE_DELETE set the ACI_WRITE |
| | |
| | | if((container.getCurrentAttributeValue() != null) && |
| | | (container.hasRights(ACI_WRITE)) && |
| | | (isAttributeDN(container.getCurrentAttributeType()))) { |
| | | String DNString=null; |
| | | try { |
| | | String DNString = |
| | | container.getCurrentAttributeValue().getStringValue(); |
| | | DNString = container.getCurrentAttributeValue().getStringValue(); |
| | | DN tmpDN = DN.decode(DNString); |
| | | //Have a valid DN, compare to clientDN to see if the ACI_SELF |
| | | //right should be set. |
| | |
| | | container.setRights(container.getRights() | ACI_SELF); |
| | | } |
| | | } catch (DirectoryException ex) { |
| | | return false; |
| | | //Log a message and keep going. |
| | | int msgID = MSGID_ACI_NOT_VALID_DN; |
| | | String message = getMessage(msgID, DNString); |
| | | logError(ErrorLogCategory.ACCESS_CONTROL, |
| | | ErrorLogSeverity.INFORMATIONAL, message, msgID); |
| | | } |
| | | } |
| | | |
| | |
| | | //only do a proxy check if the right is not set to ACI_PROXY and the |
| | | //proxied authorization control has been decoded. |
| | | if(!container.hasSeenEntry()) { |
| | | if(!container.hasRights(ACI_PROXY) && |
| | | container.isProxiedAuthorization()) { |
| | | if(container.isProxiedAuthorization() && |
| | | !container.hasRights(ACI_PROXY) && |
| | | !container.hasRights(ACI_SKIP_PROXY_CHECK)) { |
| | | int currentRights=container.getRights(); |
| | | //Save the current rights so they can be put back if on success. |
| | | container.setRights(ACI_PROXY); |
| | |
| | | */ |
| | | createApplicableList(candidates,container); |
| | | /* |
| | | * Lastly, evaluate the applicable list. |
| | | * Evaluate the applicable list. |
| | | */ |
| | | return(testApplicableLists(container)); |
| | | boolean ret=testApplicableLists(container); |
| | | //Build summary string if doing geteffectiverights eval. |
| | | if(container.isGetEffectiveRightsEval()) |
| | | AciEffectiveRights.createSummary(container, ret, "main"); |
| | | return ret; |
| | | } |
| | | |
| | | /** |
| | |
| | | * |
| | | * @return True if access is allowed. |
| | | */ |
| | | private boolean accessAllowedEntry(AciLDAPOperationContainer container) { |
| | | boolean accessAllowedEntry(AciLDAPOperationContainer container) { |
| | | boolean ret=false; |
| | | //set flag that specifies this is the first attribute evaluated |
| | | //in the entry |
| | |
| | | ret=accessAllowedEntry(operationContainer); |
| | | } |
| | | } |
| | | if(ret && operation.getAttachment(OID_GET_EFFECTIVE_RIGHTS) != null) |
| | | operation.setAttachment(ALL_ATTRS_RESOURCE_ENTRY, entry ); |
| | | return ret; |
| | | } |
| | | |
| | |
| | | //method, set the seen flag to true to bypass any proxy check. |
| | | operationContainer.setSeenEntry(true); |
| | | SearchResultEntry returnEntry; |
| | | if(!skipAccessCheck(operation)) { |
| | | boolean skipCheck=skipAccessCheck(operation); |
| | | if(!skipCheck) { |
| | | returnEntry=accessAllowedAttrs(operationContainer); |
| | | } else |
| | | returnEntry=entry; |
| | | if(operationContainer.hasGetEffectiveRightsControl()) { |
| | | returnEntry = |
| | | AciEffectiveRights.addRightsToEntry(this, operation.getAttributes(), |
| | | operationContainer, returnEntry, |
| | | skipCheck); |
| | | } |
| | | return returnEntry; |
| | | } |
| | | |
| | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Called when a geteffectiverights request control was decoded. Currently |
| | | * used to save the control in the specified operation's attachment list. |
| | | * Eventually will be used to check access to the actual control. |
| | | * @param operation The operation to save the attachment to. |
| | | * @param c The request control to save. |
| | | * @return True if the control is allowed access. |
| | | */ |
| | | public boolean isGetEffectiveRightsAllowed(Operation operation, Control c) { |
| | | operation.setAttachment(OID_GET_EFFECTIVE_RIGHTS, c); |
| | | return true; |
| | | } |
| | | |
| | | //Not planned to be implemented methods. |
| | | |
| | | /** |
| | |
| | | * @return True if the ACI had a targattrfilter rule that matched. |
| | | */ |
| | | public boolean getTargAttrFiltersMatch(); |
| | | |
| | | /** |
| | | * Add the specified ACI to a list of ACIs that have a targattrfilters rule |
| | | * that matched. This is used by geteffectiverights to determine the rights |
| | | * of an attribute that possibly might evaluate to true. |
| | | * @param aci The ACI to save. |
| | | */ |
| | | public void addTargAttrFiltersMatchAci(Aci aci); |
| | | |
| | | /** |
| | | * Save the name of the last ACI that matched a targattrfilters rule. This |
| | | * is used by geteffectiverights evaluation. |
| | | * @param name The ACI's name to save. |
| | | */ |
| | | void setTargAttrFiltersAciName(String name); |
| | | |
| | | /** |
| | | * Returns true of a match context is performing a geteffectiverights |
| | | * evaluation. |
| | | * @return True if a match context is evaluating geteffectiverights. |
| | | */ |
| | | boolean isGetEffectiveRightsEval(); |
| | | } |
| | | |
| | | |
| | |
| | | targAttrFilters.hasMask(TARGATTRFILTERS_ADD)) || |
| | | (matchCtx.hasRights(ACI_WRITE_DELETE) && |
| | | targAttrFilters.hasMask(TARGATTRFILTERS_DELETE))) |
| | | ret=targAttrFilters.isApplicableMod(matchCtx); |
| | | ret=targAttrFilters.isApplicableMod(matchCtx, aci); |
| | | } |
| | | return ret; |
| | | } |
| | |
| | | else |
| | | ret = false; |
| | | } |
| | | if((isFirstAttr) && (aci.getTargets().getTargetAttr() == null)) |
| | | if((isFirstAttr) && (aci.getTargets().getTargetAttr() == null) |
| | | && aci.getTargets().getTargAttrFilters() == null) |
| | | targetMatchCtx.setEntryTestRule(true); |
| | | } |
| | | return ret; |
| New file |
| | |
| | | /* |
| | | * 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 |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.server.authorization.dseecompat; |
| | | |
| | | /** |
| | | * This class provides an enumeration of the reasons why an ACI evaluation |
| | | * returned a result from the AciHandler's testApplicableLists call. This class |
| | | * is used by a geteffectiverights aclRightsInfo attribute search to build |
| | | * a summary string. |
| | | */ |
| | | |
| | | public enum EnumEvalReason { |
| | | |
| | | /** |
| | | * There are aren't any allow ACIs. |
| | | */ |
| | | NO_ALLOW_ACIS(0), |
| | | |
| | | /** |
| | | * An deny ACI either evaluated to FAIL or to TRUE. |
| | | */ |
| | | EVALUATED_DENY_ACI(1), |
| | | |
| | | /** |
| | | * An allow evaluated to true. |
| | | */ |
| | | EVALUATED_ALLOW_ACI(2), |
| | | |
| | | /** |
| | | * None of the allow and deny ACIs evaluated to true. |
| | | */ |
| | | NO_MATCHED_ALLOWS_ACIS(3), |
| | | |
| | | /** |
| | | * No specific reason could be determined. |
| | | */ |
| | | NO_REASON(4), |
| | | |
| | | /** |
| | | * The authorization DN has bypass-acl privileges. |
| | | */ |
| | | SKIP_ACI(5); |
| | | |
| | | /** |
| | | * Create a new enumeration type for the specified result value. |
| | | * @param v The value of the result. |
| | | */ |
| | | EnumEvalReason(int v) {} |
| | | } |
| | |
| | | * operation. |
| | | * @param matchCtx The target match context containing the information |
| | | * needed to match. |
| | | * @param aci The ACI currently being evaluted for a target match. |
| | | * @return True if this TargAttrFitlers object is applicable to this |
| | | * target match context. |
| | | */ |
| | | public boolean isApplicableMod(AciTargetMatchContext matchCtx) { |
| | | public boolean isApplicableMod(AciTargetMatchContext matchCtx, |
| | | Aci aci) { |
| | | //Get the targFitlerList corresponding to this context's rights. |
| | | TargAttrFilterList attrFilterList=getTargAttrFilterList(matchCtx); |
| | | //If the list is empty return true and go on to the targattr check |
| | |
| | | attrMatched=matchFilterAttributeValue(attrType, value, filter); |
| | | //This flag causes any targattr checks to be bypassed in AciTargets. |
| | | matchCtx.setTargAttrFiltersMatch(true); |
| | | //Doing a geteffectiverights eval, save the ACI and the name |
| | | //in the context. |
| | | if(matchCtx.isGetEffectiveRightsEval()) { |
| | | matchCtx.setTargAttrFiltersAciName(aci.getName()); |
| | | matchCtx.addTargAttrFiltersMatchAci(aci); |
| | | } |
| | | if(op.equals(EnumTargetOperator.NOT_EQUALITY)) |
| | | attrMatched = !attrMatched; |
| | | } |
| | |
| | | */ |
| | | 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. |
| | |
| | | //Add each element of array to attributes HashSet |
| | | //after converting it to AttributeType. |
| | | arrayToAttributeTypes(attributeArray); |
| | | //Must be either all operational attrs or all user attrs, |
| | | //but not both. |
| | | if(!opAttributes.isEmpty() && !attributes.isEmpty()) { |
| | | int msgID = |
| | | MSGID_ACI_TARGETATTR_INVALID_OP_USER_ATTR; |
| | | String message = getMessage(msgID, attrString); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | //Inequality not allowed with operational attrs. |
| | | if(!opAttributes.isEmpty() && |
| | | operator.equals(EnumTargetOperator.NOT_EQUALITY)) { |
| | | int msgID = |
| | | MSGID_ACI_TARGATTR_INVALID_OP_ATTR_INEQUALITY; |
| | | String message = getMessage(msgID, attrString); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } else { |
| | | int msgID = |
| | | MSGID_ACI_SYNTAX_INVALID_TARGETATTRKEYWORD_EXPRESSION; |
| | |
| | | |
| | | /** |
| | | * Converts each element of an array of attribute type strings |
| | | * to attribute types and adds them to the attributes HashSet. |
| | | * to attribute types and adds them to either the attributes HashSet or |
| | | * the operational attributes HashSet if they are operational. |
| | | * @param attributeArray The array of attribute type strings. |
| | | */ |
| | | private void arrayToAttributeTypes(String[] attributeArray) { |
| | |
| | | DirectoryServer.getAttributeType(attribute)) == null) |
| | | attributeType = |
| | | DirectoryServer.getDefaultAttributeType(attribute); |
| | | if(attributeType.isOperational()) |
| | | opAttributes.add(attributeType); |
| | | else |
| | | attributes.add(attributeType); |
| | | } |
| | | } |
| | |
| | | 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. |
| | |
| | | * |
| | | * targetattrs="*" |
| | | * |
| | | * is seen when an ACI is parsed. If the isAllAttributes boolean is |
| | | * true, the second check is skipped and the TargetAttr's operator is |
| | | * checked to see if the method should return false (NOT_EQUALITY) |
| | | * instead of true. |
| | | * is seen when an ACI is parsed. This boolean only applies to |
| | | * non-operational attribute types. If the attribute type being evaluated |
| | | * and the isAllAttributes is true, then the evaluation will return false |
| | | * because operational attributes must be explicity defined. |
| | | * |
| | | * If the isAllAttributes boolean is false, then the TargeAttr's |
| | | * If the isAllAttributes boolean is true (and the attribute is |
| | | * non-operational), the second check is skipped and the TargetAttr's |
| | | * operator is checked to see if the method should return false |
| | | * (NOT_EQUALITY) instead of true. |
| | | * |
| | | * If the isAllAttributes boolean is false, then the attribute type is |
| | | * checked to see if it is operational. If it is, then the operational |
| | | * HashSet is searched to see if it contains the operational attribute |
| | | * type. If it is found then true is returned, else false is returned |
| | | * if it isn't found. The NOT_EQUALITY operator is invalid for operational |
| | | * attribute types and is not checked. |
| | | * |
| | | * If the attribute is not operational, then the TargeAttr's user |
| | | * attribute type HashSet is searched to see if it contains the |
| | | * specified attribute type. That result could be negated depending |
| | | * on if the TargetAttr's operator is NOT_EQUALITY. |
| | |
| | | * TargetAttr's operator value applied to the test result. |
| | | */ |
| | | public static boolean isApplicable(AttributeType a, |
| | | TargetAttr targetAttr) { |
| | | TargetAttr targetAttr) { |
| | | boolean ret; |
| | | if(targetAttr.isAllAttributes()) { |
| | | //If it is an operational attribute, then access is denied for all |
| | | //attributes wild-card. Operational attributes must be |
| | | // explicitly defined. |
| | | if(a.isOperational()) { |
| | | ret=false; |
| | | } else |
| | | ret = |
| | | !targetAttr.getOperator().equals(EnumTargetOperator.NOT_EQUALITY); |
| | | } else { |
| | | //If it is an operational attribute, then access is denied for all |
| | | //attributes wild-card. Operational attributes must be |
| | | // explicitly defined and cannot be negated. |
| | | if(a.isOperational()) { |
| | | ret=false; |
| | | } else |
| | | ret = |
| | | !targetAttr.getOperator().equals(EnumTargetOperator.NOT_EQUALITY); |
| | | } else { |
| | | ret=false; |
| | | HashSet<AttributeType> attributes=targetAttr.getAttributes(); |
| | | if(attributes.contains(a)) |
| | | HashSet<AttributeType> opAttributes=targetAttr.getOpAttributes(); |
| | | //Check if the attribute is operational, if so check the |
| | | //operation HashSet. |
| | | if(a.isOperational()) { |
| | | if(opAttributes.contains(a)) |
| | | ret=true; |
| | | } else { |
| | | if(attributes.contains(a)) |
| | | ret=true; |
| | | if(targetAttr.getOperator().equals(EnumTargetOperator.NOT_EQUALITY)) |
| | | if(targetAttr.getOperator().equals(EnumTargetOperator.NOT_EQUALITY)) |
| | | ret = !ret; |
| | | } |
| | | } |
| | | } |
| | | return ret; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * 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 |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.server.controls; |
| | | |
| | | import org.opends.server.types.*; |
| | | import org.opends.server.protocols.asn1.ASN1OctetString; |
| | | import org.opends.server.protocols.asn1.ASN1Element; |
| | | import org.opends.server.protocols.asn1.ASN1Exception; |
| | | import org.opends.server.protocols.ldap.LDAPResultCode; |
| | | import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS; |
| | | import static org.opends.server.util.Validator.ensureNotNull; |
| | | import static org.opends.server.util.StaticUtils.toLowerCase; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import static org.opends.server.messages.ProtocolMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import static org.opends.server.loggers.debug.DebugLogger.debugEnabled; |
| | | import static org.opends.server.loggers.debug.DebugLogger.debugCaught; |
| | | |
| | | import java.util.List; |
| | | import java.util.ArrayList; |
| | | import java.util.LinkedList; |
| | | |
| | | /** |
| | | * This class partially implements the geteffectiverights control as defined |
| | | * in draft-ietf-ldapext-acl-model-08.txt. The main differences are: |
| | | * |
| | | * - The response control is not supported. Instead the dseecompat |
| | | * geteffectiverights control implementation creates attributes containing |
| | | * right information strings and adds those attributes to the |
| | | * entry being returned. The attribute type names are dynamically created; |
| | | * see the dseecompat's AciGetEffectiveRights class for details. |
| | | * |
| | | * - The dseecompat implementation allows additional attribute types |
| | | * in the request control for which rights information can be returned. |
| | | * These are known as the specified attribute types. |
| | | * |
| | | * The dseecompat request control value is the following: |
| | | * |
| | | * <BR> |
| | | * <PRE> |
| | | * GetRightsControl ::= SEQUENCE { |
| | | * authzId authzId |
| | | * attributes SEQUENCE OF AttributeType |
| | | * } |
| | | * |
| | | * -- Only the "dn:DN form is supported. |
| | | * |
| | | * </PRE> |
| | | * |
| | | **/ |
| | | public class GetEffectiveRights extends Control { |
| | | |
| | | //The DN representing the authzId. May be null. |
| | | private DN authzDN=null; |
| | | |
| | | //The list of additional attribute types to return rights for. May be null. |
| | | private List<AttributeType> attrs=null; |
| | | |
| | | /** |
| | | * Create a new geteffectiverights control with null authzDN and null |
| | | * attribute list. |
| | | */ |
| | | public GetEffectiveRights() { |
| | | super(OID_GET_EFFECTIVE_RIGHTS, true, null); |
| | | } |
| | | |
| | | /** |
| | | * Create a new geteffectiverights control with the specified raw octet |
| | | * string, an authzDN and an attribute list. |
| | | * |
| | | * @param val The octet string repsentation of the control value. |
| | | * |
| | | * @param authzDN The authzDN. |
| | | * |
| | | * @param attrs The list of additional attributes to be returned. |
| | | */ |
| | | public GetEffectiveRights(ASN1OctetString val, DN authzDN, |
| | | List<AttributeType> attrs) { |
| | | super(OID_GET_EFFECTIVE_RIGHTS, true, val); |
| | | this.authzDN=authzDN; |
| | | this.attrs=attrs; |
| | | } |
| | | |
| | | /** |
| | | * Return the authzDN parsed from the control. |
| | | * |
| | | * @return The DN representing the authzId. |
| | | */ |
| | | public DN getAuthzDN () { |
| | | return authzDN; |
| | | } |
| | | |
| | | /** |
| | | * Return the requested additional attributes parsed from the control. Known |
| | | * as the specified attributes. |
| | | * |
| | | * @return The list containing any additional attributes to return rights |
| | | * about. |
| | | */ |
| | | public List<AttributeType> getAttributes() { |
| | | return attrs; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Decodes the provided ASN1 element. Assume that it is a ASN1 sequence |
| | | * of attributetypes. |
| | | * |
| | | * @param attributeElement The ASN1 element to be decoded. |
| | | * |
| | | * @return A list of attribute types to process rights of. |
| | | * |
| | | * @throws ASN1Exception If the attribute element cannot be decoded as a |
| | | * sequence. |
| | | */ |
| | | private static |
| | | List<AttributeType> decodeAttributeSequence(ASN1Element attributeElement) |
| | | throws ASN1Exception { |
| | | List<AttributeType> attributeList = new LinkedList<AttributeType>(); |
| | | //Decode the sequence element and put the individual elements in array. |
| | | ArrayList<ASN1Element> attrElems = |
| | | attributeElement.decodeAsSequence().elements(); |
| | | int numAttrElements = attrElems.size(); |
| | | for(int i=0; i < numAttrElements; i++) { |
| | | //Decode as an octet string. |
| | | ASN1OctetString tmp=attrElems.get(i).decodeAsOctetString(); |
| | | //Get an attribute type for it and add to the list. |
| | | AttributeType attributeType; |
| | | if((attributeType = |
| | | DirectoryServer.getAttributeType(tmp.toString())) == null) |
| | | attributeType = |
| | | DirectoryServer.getDefaultAttributeType(tmp.toString()); |
| | | attributeList.add(attributeType); |
| | | } |
| | | return attributeList; |
| | | } |
| | | |
| | | /** |
| | | * Decodes the request control's value octet string into a GetEffectiveRights |
| | | * class. It assumes that it is an ASN1 sequence as described in class |
| | | * description. |
| | | * |
| | | * @param val The octet string repsentation of the control value. |
| | | * |
| | | * @return A decoded GetEffectiveRights class representing the request |
| | | * control. |
| | | * |
| | | * @throws LDAPException If the request control's value contains errors |
| | | * causing a valid GetEffectiveRights class to not |
| | | * be created. |
| | | */ |
| | | private static |
| | | GetEffectiveRights decodeValueSequence(ASN1OctetString val ) |
| | | throws LDAPException { |
| | | DN authzDN; |
| | | List<AttributeType> attrs=null; |
| | | String authzIDString=""; |
| | | try { |
| | | ASN1Element sequence = ASN1Element.decode(val.value()); |
| | | ArrayList<ASN1Element> elements = |
| | | sequence.decodeAsSequence().elements(); |
| | | ASN1OctetString authzID = elements.get(0).decodeAsOctetString(); |
| | | //There is an sequence containing an attribute list, try to decode it. |
| | | if(elements.size() == 2) |
| | | attrs=decodeAttributeSequence(elements.get(1)); |
| | | authzIDString = authzID.stringValue(); |
| | | String lowerAuthzIDString = toLowerCase(authzIDString); |
| | | //Make sure authzId starts with "dn:" and is a valid DN. |
| | | if (lowerAuthzIDString.startsWith("dn:")) |
| | | authzDN = DN.decode(authzIDString.substring(3)); |
| | | else { |
| | | int msgID = MSGID_GETEFFECTIVERIGHTS_INVALID_AUTHZID; |
| | | String message = getMessage(msgID, authzID); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, message); |
| | | } |
| | | } catch (ASN1Exception e) { |
| | | if (debugEnabled()) { |
| | | debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | |
| | | int msgID = MSGID_GETEFFECTIVERIGHTS_DECODE_ERROR; |
| | | String message = getMessage(msgID, e.getMessage()); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, message); |
| | | } catch (DirectoryException de) { |
| | | if (debugEnabled()) { |
| | | debugCaught(DebugLogLevel.ERROR, de); |
| | | } |
| | | |
| | | int msgID = MSGID_CANNOT_DECODE_GETEFFECTIVERIGHTS_AUTHZID_DN; |
| | | String message = |
| | | getMessage(msgID, authzIDString.substring(3), de.getErrorMessage()); |
| | | throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, msgID, message); |
| | | } |
| | | return new GetEffectiveRights(val, authzDN, attrs); |
| | | } |
| | | |
| | | /** |
| | | * Decodes the request control's value into a GetEffectiveRights class. |
| | | * |
| | | * @param control The control class representing the request control. |
| | | * |
| | | * @return A decoded GetEffectiveRights class representing the request |
| | | * control. |
| | | * |
| | | * @throws LDAPException If the request control's value contains errors |
| | | * causing a valid GetEffectiveRights class to not |
| | | * be created. |
| | | */ |
| | | public static |
| | | GetEffectiveRights decodeControl(Control control) throws LDAPException { |
| | | ensureNotNull(control); |
| | | ASN1OctetString value=control.getValue(); |
| | | //If the value is null create a GetEffectiveRights class with null |
| | | //authzDN and attribute list, else try to decode the value. |
| | | if(value == null) |
| | | return new GetEffectiveRights(); |
| | | else |
| | | return GetEffectiveRights.decodeValueSequence(value); |
| | | } |
| | | } |
| | |
| | | import org.opends.server.types.Operation; |
| | | import org.opends.server.types.SearchResultEntry; |
| | | import org.opends.server.types.SearchResultReference; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.*; |
| | | |
| | | /** |
| | | * This class implements a default access control provider for the |
| | |
| | | public boolean isProxiedAuthAllowed(Operation operation, Entry entry) { |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isGetEffectiveRightsAllowed(Operation operation, Control c) { |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | |
| | | import org.opends.server.api.plugin.PreParsePluginResult; |
| | | import org.opends.server.api.plugin.SearchEntryPluginResult; |
| | | import org.opends.server.api.plugin.SearchReferencePluginResult; |
| | | import org.opends.server.controls.AccountUsableResponseControl; |
| | | import org.opends.server.controls.LDAPAssertionRequestControl; |
| | | import org.opends.server.controls.MatchedValuesControl; |
| | | import org.opends.server.controls.PersistentSearchControl; |
| | | import org.opends.server.controls.ProxiedAuthV1Control; |
| | | import org.opends.server.controls.ProxiedAuthV2Control; |
| | | import org.opends.server.controls.*; |
| | | import org.opends.server.protocols.asn1.ASN1OctetString; |
| | | import org.opends.server.protocols.ldap.LDAPFilter; |
| | | import org.opends.server.types.Attribute; |
| | |
| | | else if (oid.equals(OID_VIRTUAL_ATTRS_ONLY)) |
| | | { |
| | | virtualAttributesOnly = true; |
| | | } else if(oid.equals(OID_GET_EFFECTIVE_RIGHTS)) { |
| | | GetEffectiveRights effectiveRightsControl; |
| | | if (c instanceof GetEffectiveRights) |
| | | { |
| | | effectiveRightsControl = (GetEffectiveRights) c; |
| | | } |
| | | else |
| | | { |
| | | try |
| | | { |
| | | effectiveRightsControl = GetEffectiveRights.decodeControl(c); |
| | | } |
| | | catch (LDAPException le) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | debugCaught(DebugLogLevel.ERROR, le); |
| | | } |
| | | |
| | | setResultCode(ResultCode.valueOf(le.getResultCode())); |
| | | appendErrorMessage(le.getMessage()); |
| | | |
| | | break searchProcessing; |
| | | } |
| | | } |
| | | |
| | | if (!AccessControlConfigManager.getInstance() |
| | | .getAccessControlHandler(). |
| | | isGetEffectiveRightsAllowed(this, effectiveRightsControl)) { |
| | | setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS); |
| | | int msgID = |
| | | MSGID_SEARCH_EFFECTIVERIGHTS_INSUFFICIENT_ACCESS_RIGHTS; |
| | | appendErrorMessage(getMessage(msgID, String.valueOf(baseDN))); |
| | | |
| | | skipPostOperation = true; |
| | | break searchProcessing; |
| | | } |
| | | } |
| | | |
| | | // NYI -- Add support for additional controls. |
| | |
| | | public static final int MSGID_ACI_HANDLER_CANNOT_LOCK_NEW_SUPERIOR_USER = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 72; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if a attribute type with |
| | | * a DN syntax failed to DN decode in the selfwrite access checking. This |
| | | * takes one argument, which is the invalid DN string. |
| | | */ |
| | | public static final int MSGID_ACI_NOT_VALID_DN = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 73; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if a targetattr |
| | | * keyword expression contains both operational and user attribute |
| | | * types. This takes one argument, which is the targetattr expression string. |
| | | */ |
| | | public static final int MSGID_ACI_TARGETATTR_INVALID_OP_USER_ATTR = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 74; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if a targetattr |
| | | * keyword expression performs both an inequality operation using |
| | | * operational attribute types. This takes one argument, which is the |
| | | * targetattr expression string. |
| | | */ |
| | | public static final int MSGID_ACI_TARGATTR_INVALID_OP_ATTR_INEQUALITY = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 75; |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined in |
| | | * this class. |
| | |
| | | |
| | | registerMessage(MSGID_ACI_HANDLER_CANNOT_LOCK_NEW_SUPERIOR_USER, |
| | | "Unable to obtain a lock on the ModifyDN new superior entry %s"); |
| | | |
| | | registerMessage(MSGID_ACI_NOT_VALID_DN, |
| | | "Selfwrite check skipped because an attribute \"%s\" with a " + |
| | | "distinguished name syntax was not a valid DN"); |
| | | |
| | | registerMessage(MSGID_ACI_TARGETATTR_INVALID_OP_USER_ATTR, |
| | | "The provided Access Control Instruction (ACI) " + |
| | | "targetattr expression value \"%s\" is invalid because" + |
| | | " the expression contains both operational attribute types" + |
| | | " and user attribute types"); |
| | | |
| | | registerMessage(MSGID_ACI_TARGATTR_INVALID_OP_ATTR_INEQUALITY, |
| | | "The provided Access Control Instruction (ACI) " + |
| | | "targetattr expression value \"%s\" is invalid because" + |
| | | " the expression performs an inequality operation using " + |
| | | "operational attribute types"); |
| | | } |
| | | } |
| | |
| | | CATEGORY_MASK_CORE | SEVERITY_MASK_INFORMATIONAL | 610; |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if a search |
| | | * operation cannot be processed due to insufficient access rights caused |
| | | * by an access control check on the geteffectiverights control. This message |
| | | * takes a single argument, the name of the search operation's base entry. |
| | | */ |
| | | public static final |
| | | int MSGID_SEARCH_EFFECTIVERIGHTS_INSUFFICIENT_ACCESS_RIGHTS = |
| | | CATEGORY_MASK_CORE | SEVERITY_MASK_SEVERE_ERROR | 611; |
| | | |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined |
| | |
| | | "The entry %s cannot be modified due to insufficient access rights"); |
| | | registerMessage(MSGID_SEARCH_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS, |
| | | "The entry %s cannot be searched due to insufficient access rights"); |
| | | |
| | | |
| | | registerMessage(MSGID_SEARCH_EFFECTIVERIGHTS_INSUFFICIENT_ACCESS_RIGHTS, |
| | | "The entry %s cannot be searched due to insufficient access rights"); |
| | | registerMessage(MSGID_BIND_OPERATION_INSECURE_SIMPLE_BIND, |
| | | "Rejecting a simple bind request for user %s because the " + |
| | | "password policy requires secure authentication"); |
| | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an error occurs parsing |
| | | * the geteffectiverights authzid because it does not start with the required |
| | | * string "dn:". This takes one argument, which is the authzid string. |
| | | */ |
| | | public static final int MSGID_GETEFFECTIVERIGHTS_INVALID_AUTHZID = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 424; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an error occurs while |
| | | * attempting to decode the value of an geteffectiverights request control. |
| | | * This takes a single argument, which is a message explaining the problem |
| | | * that occurred. |
| | | */ |
| | | public static final int MSGID_GETEFFECTIVERIGHTS_DECODE_ERROR = |
| | | CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_INFORMATIONAL | 425; |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an error occurs while |
| | | * trying to decode the geteffectiverights authzid DN string. This takes two |
| | | * arguments, which are the authzid string and a message explaining the |
| | | * problem that was encountered. |
| | | */ |
| | | public static final int MSGID_CANNOT_DECODE_GETEFFECTIVERIGHTS_AUTHZID_DN = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 426; |
| | | |
| | | |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined in this |
| | | * class. |
| | | */ |
| | |
| | | registerMessage(MSGID_VLVRES_CONTROL_CANNOT_DECODE_VALUE, |
| | | "Unable to process the provided VLV response control " + |
| | | "because an error occurred while attempting to decode " + |
| | | "the control value: %s"); } |
| | | "the control value: %s"); |
| | | registerMessage(MSGID_GETEFFECTIVERIGHTS_INVALID_AUTHZID, |
| | | "The authorization ID \"%s\" contained in the " + |
| | | "geteffectiverights control is invalid because it does" + |
| | | " not start with \"dn:\" to indicate a user DN"); |
| | | registerMessage(MSGID_GETEFFECTIVERIGHTS_DECODE_ERROR, |
| | | "Cannot decode the provided geteffectiverights " + |
| | | "request control: %s"); |
| | | registerMessage(MSGID_CANNOT_DECODE_GETEFFECTIVERIGHTS_AUTHZID_DN, |
| | | "Unable to decode authzid DN string \"%s\" as a valid " + |
| | | "distinguished name: %s"); } |
| | | |
| | | |
| | | } |
| | | |
| | |
| | | public static final int MSGID_LDIFIMPORT_CANNOT_READ_FILE = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 887; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used as the description of the |
| | | * geteffectiverights control authzid argument. This does not take any |
| | | * arguments. |
| | | */ |
| | | public static final int MSGID_DESCRIPTION_EFFECTIVERIGHTS_USER = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 888; |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used as the description of the |
| | | * geteffectiverights control specific attribute list argument. This does |
| | | * not take any arguments. |
| | | */ |
| | | public static final int MSGID_DESCRIPTION_EFFECTIVERIGHTS_ATTR = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 889; |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used as the description of the |
| | | * geteffectiverights authzid when it does not start with the required string |
| | | * "dn:". This takes a single argument, which is the authzid string. |
| | | */ |
| | | public static final int MSGID_EFFECTIVERIGHTS_INVALID_AUTHZID = |
| | | CATEGORY_MASK_TOOLS | SEVERITY_MASK_MILD_ERROR | 890; |
| | | |
| | | |
| | | /** |
| | |
| | | |
| | | registerMessage(MSGID_LDIFIMPORT_CANNOT_READ_FILE, |
| | | "The specified LDIF file %s cannot be read"); |
| | | |
| | | registerMessage(MSGID_DESCRIPTION_EFFECTIVERIGHTS_USER, |
| | | "Use geteffectiverights control with the provided " + |
| | | "authzid"); |
| | | |
| | | registerMessage(MSGID_DESCRIPTION_EFFECTIVERIGHTS_ATTR, |
| | | "Specifies geteffectiverights control specific " + |
| | | "attribute list"); |
| | | |
| | | registerMessage(MSGID_EFFECTIVERIGHTS_INVALID_AUTHZID, |
| | | "The authorization ID \"%s\" contained in the " + |
| | | "geteffectiverights control is invalid because it does" + |
| | | " not start with \"dn:\" to indicate a user DN"); |
| | | } |
| | | } |
| | | |
| | |
| | | import org.opends.server.protocols.ldap.SearchResultDoneProtocolOp; |
| | | import org.opends.server.protocols.ldap.SearchResultEntryProtocolOp; |
| | | import org.opends.server.protocols.ldap.SearchResultReferenceProtocolOp; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.DebugLogLevel; |
| | | import org.opends.server.types.LDAPException; |
| | | import org.opends.server.types.NullOutputStream; |
| | | import org.opends.server.types.*; |
| | | |
| | | import static org.opends.server.loggers.debug.DebugLogger.*; |
| | | import static org.opends.server.messages.MessageHandler.*; |
| | |
| | | StringArgument trustStorePath = null; |
| | | StringArgument trustStorePassword = null; |
| | | StringArgument vlvDescriptor = null; |
| | | StringArgument effectiveRightsUser = null; |
| | | StringArgument effectiveRightsAttrs = null; |
| | | |
| | | |
| | | // Create the command-line argument parser for use with this program. |
| | |
| | | "{controloid[:criticality[:value|::b64value|:<fileurl]]}", |
| | | null, null, MSGID_DESCRIPTION_CONTROLS); |
| | | argParser.addArgument(controlStr); |
| | | effectiveRightsUser = |
| | | new StringArgument("effectiveRightsUser", |
| | | OPTION_SHORT_EFFECTIVERIGHTSUSER, |
| | | OPTION_LONG_EFFECTIVERIGHTSUSER, false, false, true, |
| | | "{authzid}", null, null, |
| | | MSGID_DESCRIPTION_EFFECTIVERIGHTS_USER ); |
| | | argParser.addArgument(effectiveRightsUser); |
| | | |
| | | effectiveRightsAttrs = |
| | | new StringArgument("effectiveRightsAttrs", |
| | | OPTION_SHORT_EFFECTIVERIGHTSATTR, |
| | | OPTION_LONG_EFFECTIVERIGHTSATTR, false, true, true, |
| | | "{attribute}", null, null, |
| | | MSGID_DESCRIPTION_EFFECTIVERIGHTS_ATTR ); |
| | | argParser.addArgument(effectiveRightsAttrs); |
| | | |
| | | version = new IntegerArgument("version", 'V', "version", false, false, |
| | | true, "{version}", 3, null, |
| | |
| | | } |
| | | } |
| | | |
| | | if(effectiveRightsUser.isPresent()) { |
| | | String authzID=effectiveRightsUser.getValue(); |
| | | if (!authzID.startsWith("dn:")) { |
| | | int msgID = MSGID_EFFECTIVERIGHTS_INVALID_AUTHZID; |
| | | String message = getMessage(msgID, authzID); |
| | | err.println(wrapText(message, MAX_LINE_WIDTH)); |
| | | err.println(argParser.getUsage()); |
| | | return 1; |
| | | } |
| | | ASN1OctetString v=null; |
| | | ASN1OctetString effectiveRightsUserVal = |
| | | new ASN1OctetString(authzID); |
| | | ASN1Sequence sequence=null; |
| | | ArrayList<ASN1Element> attrElements = |
| | | new ArrayList<ASN1Element>(); |
| | | for(String a : effectiveRightsAttrs.getValues()) |
| | | attrElements.add(new ASN1OctetString(a)); |
| | | ASN1Sequence attrSeq=new ASN1Sequence(attrElements); |
| | | ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2); |
| | | elements.add(effectiveRightsUserVal); |
| | | elements.add(attrSeq); |
| | | sequence= new ASN1Sequence(elements); |
| | | LDAPControl effectiveRightsControl = |
| | | new LDAPControl(OID_GET_EFFECTIVE_RIGHTS, false, |
| | | new ASN1OctetString(sequence.encode())); |
| | | searchOptions.getControls().add(effectiveRightsControl); |
| | | } |
| | | |
| | | if (proxyAuthzID.isPresent()) |
| | | { |
| | | ASN1OctetString proxyValue = new ASN1OctetString(proxyAuthzID.getValue()); |
| | |
| | | { |
| | | controlOID = OID_VIRTUAL_ATTRS_ONLY; |
| | | } |
| | | else if(lowerOID.equals("effectiverights") || |
| | | lowerOID.equals("geteffectiverights")) |
| | | { |
| | | controlOID = OID_GET_EFFECTIVE_RIGHTS; |
| | | } |
| | | |
| | | if (idx < 0) |
| | | { |
| | |
| | | * displayed in usage information. |
| | | */ |
| | | public static final String OPTION_VALUE_SASLOPTION = "{name=value}"; |
| | | |
| | | /** |
| | | * The value for the short option geteffectiverights control authzid. |
| | | */ |
| | | public static final char OPTION_SHORT_EFFECTIVERIGHTSUSER = 'g'; |
| | | |
| | | /** |
| | | * The value for the long option geteffectiverights control authzid. |
| | | */ |
| | | public static final String OPTION_LONG_EFFECTIVERIGHTSUSER = |
| | | "getEffectiveRightsAuthzid"; |
| | | |
| | | /** |
| | | * The value for the short option geteffectiveights control attributes. |
| | | */ |
| | | public static final char OPTION_SHORT_EFFECTIVERIGHTSATTR = 'e'; |
| | | |
| | | /** |
| | | * The value for the long option geteffectiverights control specific |
| | | * attribute list. |
| | | */ |
| | | public static final String OPTION_LONG_EFFECTIVERIGHTSATTR = |
| | | "getEffectiveRightsAttribute"; |
| | | } |
| | | |
| | |
| | | public static final String OID_PROXIED_AUTH_V2 = "2.16.840.1.113730.3.4.18"; |
| | | |
| | | |
| | | /** |
| | | * The OID for the get effective rights control. |
| | | */ |
| | | public static final String OID_GET_EFFECTIVE_RIGHTS = |
| | | "1.3.6.1.4.1.42.2.27.9.5.2"; |
| | | |
| | | |
| | | /** |
| | | * The OID for the real attributes only control. |
| New file |
| | |
| | | /* |
| | | * 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 |
| | | * |
| | | * |
| | | * Portions Copyright 2007 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.server.authorization.dseecompat; |
| | | |
| | | import org.testng.annotations.BeforeClass; |
| | | import org.testng.annotations.Test; |
| | | import org.testng.annotations.BeforeMethod; |
| | | import static org.opends.server.config.ConfigConstants.*; |
| | | import org.testng.Assert; |
| | | import static org.testng.Assert.assertEquals; |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.tools.LDAPSearch; |
| | | import org.opends.server.tools.LDAPModify; |
| | | import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS; |
| | | import static org.opends.server.util.ServerConstants.EOL; |
| | | |
| | | import java.io.*; |
| | | import java.util.ArrayList; |
| | | import java.util.Map; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | |
| | | public class GetEffectiveRightsTestCase { |
| | | private static ByteArrayOutputStream oStream = new ByteArrayOutputStream(); |
| | | private static final String DIR_MGR_DN = "cn=Directory Manager"; |
| | | private static final String PWD = "password"; |
| | | private static final String filter = "(objectclass=*)"; |
| | | private static final String base="uid=user.3,ou=People,o=test"; |
| | | private static final String user1="uid=user.1,ou=People,o=test"; |
| | | private static final String superUser="uid=superuser,ou=admins,o=test"; |
| | | private static final String[] attrList={"pager", "fax"}; |
| | | private static final String[] memberAttrList={"member"}; |
| | | private static final String entryLevel = "aclRights;entryLevel"; |
| | | private static final String attributeLevel = "aclRights;attributeLevel;"; |
| | | |
| | | //Various results for entryLevel searches. |
| | | private static final |
| | | String bypassRights = "add:1,delete:1,read:1,write:1,proxy:1"; |
| | | |
| | | private static final |
| | | String rRights = "add:0,delete:0,read:1,write:0,proxy:0"; |
| | | |
| | | private static final |
| | | String arRights = "add:1,delete:0,read:1,write:0,proxy:0"; |
| | | |
| | | private static final |
| | | String adrRights = "add:1,delete:1,read:1,write:0,proxy:0"; |
| | | |
| | | private static final |
| | | String adrwRights = "add:1,delete:1,read:1,write:1,proxy:0"; |
| | | |
| | | private static final |
| | | String allRights = "add:1,delete:1,read:1,write:1,proxy:1"; |
| | | |
| | | private static final |
| | | String ACCESS_HANDLER_DN = "cn=Access Control Handler,cn=config"; |
| | | |
| | | //Results for attributeLevel searches |
| | | private static final String srwMailAttrRights = |
| | | "search:1,read:1,compare:0,write:1," + |
| | | "selfwrite_add:1,selfwrite_delete:1,proxy:0"; |
| | | |
| | | private static final String srDescrptionAttrRights = |
| | | "search:1,read:1,compare:0,write:0," + |
| | | "selfwrite_add:0,selfwrite_delete:0,proxy:0"; |
| | | |
| | | private static final String srxFaxAttrRights = |
| | | "search:1,read:1,compare:0,write:?," + |
| | | "selfwrite_add:0,selfwrite_delete:0,proxy:0"; |
| | | |
| | | private static final String srPagerAttrRights = |
| | | "search:1,read:1,compare:0,write:0," + |
| | | "selfwrite_add:0,selfwrite_delete:0,proxy:0"; |
| | | |
| | | private static final String selfWriteAttrRights = |
| | | "search:0,read:0,compare:0,write:0," + |
| | | "selfwrite_add:1,selfwrite_delete:1,proxy:0"; |
| | | |
| | | //ACI needed to search/read aciRights attribute. |
| | | private static final |
| | | String aclRightsAci = "(targetattr=\"aclRights\")" + |
| | | "(version 3.0;acl \"aclRights access\";" + |
| | | "allow (search, read) " + |
| | | "userdn=\"ldap:///uid=superuser,ou=admins,o=test\";)"; |
| | | |
| | | //General ACI superuser to search/read. |
| | | |
| | | private static final |
| | | String readSearchAci = "(targetattr=\"*\")" + |
| | | "(version 3.0;acl \"read/search access\";" + |
| | | "allow (search, read) " + |
| | | "userdn=\"ldap:///uid=superuser,ou=admins,o=test\";)"; |
| | | |
| | | //General ACI for anonymous test. |
| | | private static final |
| | | String readSearchAnonAci = "(targetattr=\"*\")" + |
| | | "(version 3.0;acl \"anonymous read/search access\";" + |
| | | "allow (search, read) " + |
| | | "userdn=\"ldap:///anyone\";)"; |
| | | |
| | | //Test ACIs. |
| | | private static final |
| | | String addAci = "(version 3.0;acl \"add access\";" + |
| | | "allow (add) " + |
| | | "userdn=\"ldap:///uid=superuser,ou=admins,o=test\";)"; |
| | | |
| | | private static final |
| | | String delAci = "(version 3.0;acl \"delete access\";" + |
| | | "allow (delete) " + |
| | | "userdn=\"ldap:///uid=superuser,ou=admins,o=test\";)"; |
| | | |
| | | private static final |
| | | String writeAci = "(version 3.0;acl \"write access\";" + |
| | | "allow (write) " + |
| | | "userdn=\"ldap:///uid=superuser,ou=admins,o=test\";)"; |
| | | |
| | | private static final |
| | | String writeMailAci = "(targetattr=\"mail\")" + |
| | | "(version 3.0;acl \"write mail access\";" + |
| | | "allow (write) " + |
| | | "userdn=\"ldap:///uid=superuser,ou=admins,o=test\";)"; |
| | | |
| | | private static final |
| | | String proxyAci = "(version 3.0;acl \"proxy access\";" + |
| | | "allow (proxy) " + |
| | | "userdn=\"ldap:///uid=superuser,ou=admins,o=test\";)"; |
| | | |
| | | private static final |
| | | String faxTargAttrAci = |
| | | "(targattrfilters=\"add=fax:(fax=*), del=fax:(fax=*)\")" + |
| | | "(version 3.0;acl \"allow write fax\";" + |
| | | "allow (write)" + |
| | | "userdn=\"ldap:///uid=superuser,ou=admins,o=test\";)"; |
| | | |
| | | private static final |
| | | String pagerTargAttrAci = |
| | | "(targattrfilters=\"add=pager:(pager=*), del=pager:(pager=*)\")" + |
| | | "(version 3.0;acl \"deny write pager\";" + |
| | | "deny (write)" + |
| | | "userdn=\"ldap:///uid=superuser,ou=admins,o=test\";)"; |
| | | |
| | | private static final |
| | | String selfWriteAci = "(targetattr=\"member\")" + |
| | | "(version 3.0; acl \"selfwrite\"; allow(selfwrite)" + "" + |
| | | "userdn=\"ldap:///uid=user.1,ou=People,o=test\";)"; |
| | | |
| | | @BeforeClass |
| | | public void setupClass() throws Exception { |
| | | TestCaseUtils.startServer(); |
| | | deleteAttrFromEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI); |
| | | addEntries(); |
| | | } |
| | | |
| | | @BeforeMethod |
| | | public void removeAcis() throws Exception { |
| | | deleteAttrFromEntry("ou=People,o=test", "aci"); |
| | | } |
| | | |
| | | /** |
| | | * Test entry level using the -g param and anonymous dn as the authzid. |
| | | * @throws Exception If the search result is empty or a right string |
| | | * doesn't match the expected value. |
| | | */ |
| | | @Test() |
| | | public void testAnonEntryLevelParams() throws Exception { |
| | | String aciLdif=makeAddAciLdif("aci", "ou=People,o=test", readSearchAnonAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | String userResults = |
| | | LDAPSearchParams(DIR_MGR_DN, PWD, null, "dn:", null, |
| | | base, filter, "aclRights"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | HashMap<String, String> attrMap=getAttrMap(userResults); |
| | | checkEntryLevel(attrMap, rRights); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * Test entry level using the -g param and superuser dn as the authzid. |
| | | * @throws Exception If the search result is empty or a right string |
| | | * doesn't match the expected value. |
| | | */ |
| | | @Test() |
| | | public void testSuEntryLevelParams() throws Exception { |
| | | String aciLdif=makeAddAciLdif("aci", "ou=People,o=test", aclRightsAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", readSearchAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | String userResults = |
| | | LDAPSearchParams(superUser, PWD, null, "dn: " + superUser, null, |
| | | base, filter, "aclRights"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | HashMap<String, String> attrMap=getAttrMap(userResults); |
| | | checkEntryLevel(attrMap, rRights); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", addAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | userResults = |
| | | LDAPSearchParams(superUser, PWD, null, "dn: " + superUser, null, |
| | | base, filter, "aclRights"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | attrMap=getAttrMap(userResults); |
| | | checkEntryLevel(attrMap, arRights); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", delAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | userResults = |
| | | LDAPSearchParams(superUser, PWD, null, "dn: " + superUser, null, |
| | | base, filter, "aclRights"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | attrMap=getAttrMap(userResults); |
| | | checkEntryLevel(attrMap, adrRights); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", writeAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | userResults = |
| | | LDAPSearchParams(superUser, PWD, null, "dn: " + superUser, null, |
| | | base, filter, "aclRights"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | attrMap=getAttrMap(userResults); |
| | | checkEntryLevel(attrMap, adrwRights); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", proxyAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | userResults = |
| | | LDAPSearchParams(superUser, PWD, null, "dn: " + superUser, null, |
| | | base, filter, "aclRights"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | attrMap=getAttrMap(userResults); |
| | | checkEntryLevel(attrMap, allRights); |
| | | } |
| | | |
| | | /** |
| | | * Test entry level using the control OID only (no authzid specified). |
| | | * Should use the bound user (superuser) as the authzid. |
| | | * @throws Exception If the search result is empty or a right string |
| | | * doesn't match the expected value. |
| | | */ |
| | | @Test() |
| | | public void testSuEntryLevelCtrl() throws Exception { |
| | | String aciLdif=makeAddAciLdif("aci", "ou=People,o=test", aclRightsAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", readSearchAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | String userResults = |
| | | LDAPSearchCtrl(superUser, PWD, null, OID_GET_EFFECTIVE_RIGHTS, |
| | | base, filter, "aclRights"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | HashMap<String, String> attrMap=getAttrMap(userResults); |
| | | checkEntryLevel(attrMap, rRights); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", addAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | userResults = |
| | | LDAPSearchCtrl(superUser, PWD, null, OID_GET_EFFECTIVE_RIGHTS, |
| | | base, filter, "aclRights"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | attrMap=getAttrMap(userResults); |
| | | checkEntryLevel(attrMap, arRights); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", delAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | userResults = |
| | | LDAPSearchCtrl(superUser, PWD, null, OID_GET_EFFECTIVE_RIGHTS, |
| | | base, filter, "aclRights"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | attrMap=getAttrMap(userResults); |
| | | checkEntryLevel(attrMap, adrRights); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", writeAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | userResults = |
| | | LDAPSearchCtrl(superUser, PWD, null, OID_GET_EFFECTIVE_RIGHTS, |
| | | base, filter, "aclRights"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | attrMap=getAttrMap(userResults); |
| | | checkEntryLevel(attrMap, adrwRights); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", proxyAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | userResults = |
| | | LDAPSearchCtrl(superUser, PWD, null, OID_GET_EFFECTIVE_RIGHTS, |
| | | base, filter, "aclRights"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | attrMap=getAttrMap(userResults); |
| | | checkEntryLevel(attrMap, allRights); |
| | | } |
| | | |
| | | /** |
| | | * Test entry level using the control OID only -- bound as a bypass user. |
| | | * Should use the bound user (DIR_MGR) as the authzid. |
| | | * @throws Exception If the search result is empty or a right string |
| | | * doesn't match the expected value. |
| | | */ |
| | | @Test() |
| | | public void testBypassEntryLevelCtrl() throws Exception { |
| | | String userResults = |
| | | LDAPSearchCtrl(DIR_MGR_DN, PWD, null, OID_GET_EFFECTIVE_RIGHTS, |
| | | base, filter, "aclRights"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | HashMap<String, String> attrMap=getAttrMap(userResults); |
| | | checkEntryLevel(attrMap, bypassRights); |
| | | } |
| | | |
| | | /** |
| | | * Test attribute level using the -g param and superuser dn as the authzid. |
| | | * The attributes used are mail and description. Mail should show write |
| | | * access allowed, description should show write access not allowed. |
| | | * @throws Exception If the search result is empty or a right string |
| | | * doesn't match the expected value. |
| | | */ |
| | | @Test() |
| | | public void testSuAttrLevelParams() throws Exception { |
| | | String aciLdif=makeAddAciLdif("aci", "ou=People,o=test", aclRightsAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", readSearchAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", writeMailAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | String userResults = |
| | | LDAPSearchParams(superUser, PWD, null, "dn: " + superUser, null, |
| | | base, filter, "aclRights mail description"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | HashMap<String, String> attrMap=getAttrMap(userResults); |
| | | checkAttributeLevel(attrMap, "mail", srwMailAttrRights); |
| | | checkAttributeLevel(attrMap, "description", srDescrptionAttrRights); |
| | | } |
| | | |
| | | /** |
| | | * Test attribute level using the -g param and superuser dn as the authzid and |
| | | * the -e option using pager and fax. |
| | | * The attributes used are mail and description. Mail should show write |
| | | * access allowed, description should show write access not allowed. |
| | | * |
| | | * @throws Exception If the search result is empty or a right string |
| | | * doesn't match the expected value. |
| | | */ |
| | | @Test() |
| | | public void testSuAttrLevelParams2() throws Exception { |
| | | String aciLdif=makeAddAciLdif("aci", "ou=People,o=test", aclRightsAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", readSearchAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", writeMailAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", faxTargAttrAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", pagerTargAttrAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | String userResults = |
| | | LDAPSearchParams(superUser, PWD, null, "dn: " + superUser, attrList, |
| | | base, filter, "aclRights mail description"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | HashMap<String, String> attrMap=getAttrMap(userResults); |
| | | checkAttributeLevel(attrMap, "mail", srwMailAttrRights); |
| | | checkAttributeLevel(attrMap, "description", srDescrptionAttrRights); |
| | | checkAttributeLevel(attrMap, "fax", srxFaxAttrRights); |
| | | checkAttributeLevel(attrMap, "pager", srPagerAttrRights); |
| | | } |
| | | |
| | | /** |
| | | * Test selfwrite attribute level using the -g param and user.1 dn as the |
| | | * authzid and the -e option member. |
| | | * The attributes used are mail and description. Mail should show write |
| | | * access allowed, description should show write access not allowed. |
| | | * |
| | | * @throws Exception If the search result is empty or a right string |
| | | * doesn't match the expected value. |
| | | */ |
| | | @Test() |
| | | public void testSuAttrLevelParams3() throws Exception { |
| | | String aciLdif=makeAddAciLdif("aci", "ou=People,o=test", aclRightsAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", readSearchAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | aciLdif=makeAddAciLdif("aci", "ou=People,o=test", selfWriteAci); |
| | | modEntries(aciLdif, DIR_MGR_DN, PWD); |
| | | String userResults = |
| | | LDAPSearchParams(superUser, PWD, null, "dn: " + user1, memberAttrList, |
| | | base, filter, "aclRights"); |
| | | Assert.assertFalse(userResults.equals("")); |
| | | HashMap<String, String> attrMap=getAttrMap(userResults); |
| | | checkAttributeLevel(attrMap, "member", selfWriteAttrRights); |
| | | } |
| | | |
| | | private void |
| | | checkAttributeLevel(HashMap<String, String> attrMap, String attr, |
| | | String reqRightsStr) throws Exception { |
| | | String attrType=attributeLevel + attr; |
| | | String retRightsStr=attrMap.get(attrType); |
| | | Assert.assertTrue(retRightsStr.equals(reqRightsStr)); |
| | | } |
| | | |
| | | private void |
| | | checkEntryLevel(HashMap<String, String> attrMap, String reqRightsStr) |
| | | throws Exception { |
| | | String retRightsStr=attrMap.get(entryLevel); |
| | | Assert.assertTrue(retRightsStr.equals(reqRightsStr)); |
| | | } |
| | | |
| | | private HashMap<String, String> |
| | | getAttrMap(String resultString) throws Exception { |
| | | StringReader r=new StringReader(resultString); |
| | | BufferedReader br=new BufferedReader(r); |
| | | HashMap<String, String> attrMap = new HashMap<String,String>(); |
| | | try { |
| | | while(true) { |
| | | String s = br.readLine(); |
| | | if(s == null) |
| | | break; |
| | | if(s.startsWith("dn:")) |
| | | continue; |
| | | String[] a=s.split(": "); |
| | | if(a.length != 2) |
| | | break; |
| | | attrMap.put(a[0],a[1]); |
| | | } |
| | | } catch (IOException e) { |
| | | Assert.assertEquals(0, 1, e.getMessage()); |
| | | } |
| | | return attrMap; |
| | | } |
| | | |
| | | |
| | | private void addEntries() throws Exception { |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | TestCaseUtils.addEntries( |
| | | "dn: ou=People,o=test", |
| | | "objectClass: top", |
| | | "objectClass: organizationalUnit", |
| | | "ou: People", |
| | | "", |
| | | "dn: ou=admins,o=test", |
| | | "objectClass: top", |
| | | "objectClass: organizationalUnit", |
| | | "ou: admins", |
| | | "", |
| | | "dn: cn=group,ou=People,o=test", |
| | | "objectclass: top", |
| | | "objectclass: groupOfNames", |
| | | "cn: group", |
| | | "member: uid=user.1,ou=People,o=test", |
| | | "", |
| | | "dn: uid=superuser,ou=admins,o=test", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: superuser", |
| | | "givenName: superuser", |
| | | "sn: 1", |
| | | "cn: User 1", |
| | | "userPassword: password", |
| | | "ds-privilege-name: proxied-auth", |
| | | "", |
| | | "dn: uid=proxyuser,ou=admins,o=test", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: proxyuser", |
| | | "givenName: proxyuser", |
| | | "sn: 1", |
| | | "cn: User 1", |
| | | "userPassword: password", |
| | | "", |
| | | "dn: uid=user.1,ou=People,o=test", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: user.1", |
| | | "givenName: User", |
| | | "sn: 1", |
| | | "cn: User 1", |
| | | "userPassword: password", |
| | | "", |
| | | "dn: uid=user.2,ou=People,o=test", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: user.2", |
| | | "givenName: User", |
| | | "sn: 2", |
| | | "cn: User 2", |
| | | "userPassword: password", |
| | | "", |
| | | "dn: uid=user.3,ou=People,o=test", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: user.3", |
| | | "givenName: User", |
| | | "sn: 3", |
| | | "mail: user.3@test", |
| | | "description: user.3 description", |
| | | "cn: User 3", |
| | | "userPassword: password"); |
| | | } |
| | | |
| | | private String LDAPSearchCtrl(String bindDn, String bindPassword, |
| | | String proxyDN, String controlStr, |
| | | String base, String filter, String attr) |
| | | throws Exception { |
| | | ArrayList<String> argList=new ArrayList<String>(20); |
| | | argList.add("-h"); |
| | | argList.add("127.0.0.1"); |
| | | argList.add("-p"); |
| | | argList.add(String.valueOf(TestCaseUtils.getServerLdapPort())); |
| | | argList.add("-D"); |
| | | argList.add(bindDn); |
| | | argList.add("-w"); |
| | | argList.add(bindPassword); |
| | | argList.add("-T"); |
| | | if(proxyDN != null) { |
| | | argList.add("-Y"); |
| | | argList.add("dn:" + proxyDN); |
| | | } |
| | | if(controlStr != null) { |
| | | argList.add("-J"); |
| | | argList.add(controlStr); |
| | | } |
| | | argList.add("-b"); |
| | | argList.add(base); |
| | | argList.add("-s"); |
| | | argList.add("sub"); |
| | | argList.add(filter); |
| | | String[] attrs=attr.split("\\s+"); |
| | | for(String a : attrs) |
| | | argList.add(a); |
| | | String[] args = new String[argList.size()]; |
| | | oStream.reset(); |
| | | int retVal = |
| | | LDAPSearch.mainSearch(argList.toArray(args), false, oStream, oStream); |
| | | Assert.assertEquals(0, retVal, "Returned error: " + oStream.toString()); |
| | | return oStream.toString(); |
| | | } |
| | | |
| | | private String LDAPSearchParams(String bindDn, String bindPassword, |
| | | String proxyDN, String authzid, String[] attrList, |
| | | String base, String filter ,String attr) |
| | | throws Exception { |
| | | ArrayList<String> argList=new ArrayList<String>(20); |
| | | argList.add("-h"); |
| | | argList.add("127.0.0.1"); |
| | | argList.add("-p"); |
| | | argList.add(String.valueOf(TestCaseUtils.getServerLdapPort())); |
| | | argList.add("-D"); |
| | | argList.add(bindDn); |
| | | argList.add("-w"); |
| | | argList.add(bindPassword); |
| | | argList.add("-T"); |
| | | if(proxyDN != null) { |
| | | argList.add("-Y"); |
| | | argList.add("dn:" + proxyDN); |
| | | } |
| | | if(authzid != null) { |
| | | argList.add("-g"); |
| | | argList.add(authzid); |
| | | } |
| | | if(attrList != null) { |
| | | for(String a : attrList) { |
| | | argList.add("-e"); |
| | | argList.add(a); |
| | | } |
| | | } |
| | | argList.add("-b"); |
| | | argList.add(base); |
| | | argList.add("-s"); |
| | | argList.add("sub"); |
| | | argList.add(filter); |
| | | String[] attrs=attr.split("\\s+"); |
| | | for(String a : attrs) |
| | | argList.add(a); |
| | | String[] args = new String[argList.size()]; |
| | | oStream.reset(); |
| | | int retVal = |
| | | LDAPSearch.mainSearch(argList.toArray(args), false, oStream, oStream); |
| | | Assert.assertEquals(0, retVal, "Returned error: " + oStream.toString()); |
| | | return oStream.toString(); |
| | | } |
| | | |
| | | |
| | | private void modEntries(String ldif, String bindDn, String bindPassword) |
| | | throws Exception { |
| | | File tempFile = getTemporaryLdifFile(); |
| | | TestCaseUtils.writeFile(tempFile, ldif); |
| | | ArrayList<String> argList=new ArrayList<String>(20); |
| | | argList.add("-h"); |
| | | argList.add("127.0.0.1"); |
| | | argList.add("-p"); |
| | | argList.add(String.valueOf(TestCaseUtils.getServerLdapPort())); |
| | | argList.add("-D"); |
| | | argList.add(bindDn); |
| | | argList.add("-w"); |
| | | argList.add(bindPassword); |
| | | argList.add("-f"); |
| | | argList.add(tempFile.getAbsolutePath()); |
| | | String[] args = new String[argList.size()]; |
| | | ldapModify(argList.toArray(args)); |
| | | } |
| | | |
| | | |
| | | private void ldapModify(String[] args) { |
| | | oStream.reset(); |
| | | LDAPModify.mainModify(args, false, oStream, oStream); |
| | | } |
| | | |
| | | private void deleteAttrFromEntry(String dn, String attr) |
| | | throws Exception { |
| | | StringBuilder ldif = new StringBuilder(); |
| | | ldif.append(TestCaseUtils.makeLdif( |
| | | "dn: " + dn, |
| | | "changetype: modify", |
| | | "delete: " + attr)); |
| | | modEntries(ldif.toString(), DIR_MGR_DN, PWD); |
| | | } |
| | | |
| | | private static ThreadLocal<Map<String,File>> tempLdifFile = |
| | | new ThreadLocal<Map<String,File>>(); |
| | | |
| | | private File getTemporaryLdifFile() throws IOException { |
| | | Map<String,File> tempFilesForThisThread = tempLdifFile.get(); |
| | | if (tempFilesForThisThread == null) { |
| | | tempFilesForThisThread = new HashMap<String,File>(); |
| | | tempLdifFile.set(tempFilesForThisThread); |
| | | } |
| | | File tempFile = tempFilesForThisThread.get("effectiverights-tests"); |
| | | if (tempFile == null) { |
| | | tempFile = File.createTempFile("effectiverights-tests", ".ldif"); |
| | | tempFile.deleteOnExit(); |
| | | tempFilesForThisThread.put("effectiverights-tests", tempFile); |
| | | } |
| | | return tempFile; |
| | | } |
| | | |
| | | private static String makeAddAciLdif(String attr, String dn, String... acis) { |
| | | StringBuilder ldif = new StringBuilder(); |
| | | ldif.append("dn: ").append(dn).append(EOL); |
| | | ldif.append("changetype: modify").append(EOL); |
| | | ldif.append("add: ").append(attr).append(EOL); |
| | | for(String aci : acis) |
| | | ldif.append(attr).append(":").append(aci).append(EOL); |
| | | ldif.append(EOL); |
| | | return ldif.toString(); |
| | | } |
| | | } |