Initial commit of the dseecompat ACI code
| 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.ByteString; |
| | | import org.opends.server.types.DN; |
| | | import static org.opends.server.messages.MessageHandler.*; |
| | | import static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import java.util.regex.Pattern; |
| | | /** |
| | | * The Aci class represents ACI strings. |
| | | */ |
| | | public class Aci { |
| | | /* |
| | | * The body of the ACI is the version, name and permission-bind rule |
| | | * pairs. |
| | | */ |
| | | private AciBody body; |
| | | /* |
| | | * The ACI targets. |
| | | */ |
| | | private AciTargets targets=null; |
| | | /** |
| | | * The ACIs are on a linked list hashed by the ACI entry DN. |
| | | * Next points to the next Aci object in the list. |
| | | */ |
| | | /* |
| | | * TODO Remove this linked list an replace with an array |
| | | * of ACIs. |
| | | */ |
| | | Aci next = null; |
| | | /** |
| | | * Version that we support. |
| | | */ |
| | | public static final String supportedVersion="3.0"; |
| | | private String aciString; |
| | | /* |
| | | * The DN of the entry containing this ACI. |
| | | */ |
| | | private DN dn; |
| | | /* |
| | | * This regular expression is used to do a quick syntax check |
| | | * when an ACI is being decoded. |
| | | */ |
| | | private static final String aciRegex = |
| | | "^\\s*" + AciTargets.targetsRegex + "\\s*"+ |
| | | AciBody.bodyRegx + "\\s*$"; |
| | | |
| | | /** |
| | | * Construct a new Aci from the provided arguments. |
| | | * @param input The string representation of the ACI. |
| | | * @param dn The DN of entry containing the ACI. |
| | | * @param body The body of the ACI. |
| | | * @param targets The targets of the ACI. |
| | | */ |
| | | private Aci(String input, DN dn, AciBody body, AciTargets targets) { |
| | | this.aciString = input; |
| | | this.dn=dn; |
| | | this.body=body; |
| | | this.targets=targets; |
| | | } |
| | | |
| | | /** |
| | | * Decode an ACI byte string. |
| | | * @param byteString The ByteString containing the ACI string. |
| | | * @param dn DN of the ACI entry. |
| | | * @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(); |
| | | //Perform an quick pattern check against the string to catch any |
| | | //obvious syntax errors. |
| | | if (!Pattern.matches(aciRegex, input)) { |
| | | int msgID = MSGID_ACI_SYNTAX_GENERAL_PARSE_FAILED; |
| | | String message = getMessage(msgID, input); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | //Decode the body first. |
| | | AciBody body=AciBody.decode(input); |
| | | //Create a substring from the start of the string to start of |
| | | //the body. That should be the target. |
| | | String targetStr = input.substring(0, body.getMatcherStartPos()); |
| | | //Decode that target string using the substring. |
| | | AciTargets targets=AciTargets.decode(targetStr, dn); |
| | | return new Aci(input, dn, body, targets); |
| | | } |
| | | |
| | | /** |
| | | * Return the string representation of the ACI. This was the string that |
| | | * was used to create the Aci class. |
| | | * @return A string representation of the ACI. |
| | | */ |
| | | public String toString() { |
| | | return aciString; |
| | | } |
| | | |
| | | /** |
| | | * Returns the targets of the ACI. |
| | | * @return Any AciTargets of the ACI. There may be no targets |
| | | * so this might be null. |
| | | */ |
| | | public AciTargets getTargets() { |
| | | return targets; |
| | | } |
| | | |
| | | /** |
| | | * Return the DN of the entry containing the ACI. |
| | | * @return The DN of the entry containing the ACI. |
| | | */ |
| | | public DN getDN() { |
| | | return dn; |
| | | } |
| | | |
| | | /** |
| | | * Test if the given ACI is applicable using the target match information |
| | | * provided. The ACI target can have four keywords at this time: |
| | | * |
| | | * 1. target - checked in isTargetApplicable. |
| | | * 2. targetscope - checked in isTargetApplicable. |
| | | * 3. targetfilter - checked in isTargetFilterApplicable. |
| | | * 4. targetattr - checked in isTargetAttrApplicable. |
| | | * |
| | | * One and two are checked for match first. If they return true, then |
| | | * three is checked. Lastly four is checked. |
| | | * |
| | | * @param aci The ACI to test. |
| | | * @param matchCtx The target matching context containing all the info |
| | | * needed to match ACI targets. |
| | | * @return True if this ACI targets are applicable or match. |
| | | */ |
| | | public static boolean |
| | | isApplicable(Aci aci, AciTargetMatchContext matchCtx) { |
| | | return AciTargets.isTargetApplicable(aci, matchCtx) && |
| | | AciTargets.isTargetFilterApplicable(aci, matchCtx) && |
| | | AciTargets.isTargetAttrApplicable(aci, matchCtx); |
| | | } |
| | | |
| | | /** |
| | | * Check if the body of the ACI matches the rights specified. |
| | | * @param rights Bit mask representing the rights to match. |
| | | * @return True if the body's rights match one of the rights specified. |
| | | */ |
| | | public boolean hasRights(int rights) { |
| | | return body.hasRights(rights); |
| | | } |
| | | |
| | | /** |
| | | * Re-direct has access type to the body's hasAccessType method. |
| | | * @param accessType The access type to match. |
| | | * @return True if the body's hasAccessType determines a permission |
| | | * contains this access type (allow or deny are valid types). |
| | | */ |
| | | public boolean hasAccessType(EnumAccessType accessType) { |
| | | return body.hasAccessType(accessType); |
| | | } |
| | | |
| | | /** |
| | | * Evaluate this ACI using the evaluation context provided. Re-direct |
| | | * that calls the body's evaluate method. |
| | | * @param evalCtx The evaluation context to evaluate with. |
| | | * @return EnumEvalResult that contains the evaluation result of this |
| | | * aci evaluation. |
| | | */ |
| | | private EnumEvalResult evaluate(AciEvalContext evalCtx) { |
| | | return body.evaluate(evalCtx); |
| | | } |
| | | |
| | | /** |
| | | * Static class used to evaluate an ACI and evaluation context. |
| | | * @param evalCtx The context to evaluate with. |
| | | * @param aci The ACI to evaluate. |
| | | * @return EnumEvalResult that contains the evaluation result of the aci |
| | | * evaluation. |
| | | */ |
| | | public static EnumEvalResult evaluate(AciEvalContext evalCtx, Aci aci) { |
| | | return aci.evaluate(evalCtx); |
| | | } |
| | | } |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | | /** |
| | | * This class represents the body of an ACI. The body of the ACI is the |
| | | * version, name, and permission-bind rule pairs. |
| | | */ |
| | | public class AciBody { |
| | | |
| | | private static final int VERSION = 1; |
| | | private static final int NAME = 2; |
| | | private static final int PERM = 1; |
| | | private static final int RIGHTS = 2; |
| | | private static final int BINDRULE = 3; |
| | | private int startPos=0; |
| | | /* |
| | | * The name of the ACI, currently not used but parsed. |
| | | */ |
| | | private String name = null; |
| | | /* |
| | | * The version of the ACi, current not used but parsed and checked |
| | | * for 3.0. |
| | | */ |
| | | private String version = null; |
| | | /* |
| | | This structure represents a permission-bind rule pairs. There can be |
| | | several of these. |
| | | */ |
| | | private List<PermBindRulePair> permBindRulePairs; |
| | | /* |
| | | * TODO Define constants for these regular expressions to make them more |
| | | * readable. |
| | | * The regular expressions would probably be a lot easier |
| | | * to understand if you defined a number of constants for the |
| | | * individual components and then concatenated them. For example, |
| | | * "\\s*" could be defined in a constant named ZERO_OR_MORE_SPACES. |
| | | * This would also help make it easier to understand which parentheses |
| | | * were part of the regex and which were part of the ACI syntax. |
| | | */ |
| | | private static final String permissionRegex = "(\\w+)\\s*\\(([^()]+)\\)"; |
| | | private static final String bindRuleRegex = "(.+?\"[)]*)\\s*;"; |
| | | private static final String actionRegex = |
| | | "\\s*" + permissionRegex + "\\s*" + bindRuleRegex; |
| | | private static final String versionRegex = "(\\d\\.\\d)"; |
| | | private static final String versionToken = "(?i)version"; |
| | | private static final String aclToken = "(?i)acl"; |
| | | /** |
| | | * Regular expression used to parse the body of an ACI. |
| | | */ |
| | | public static final String bodyRegx = |
| | | "\\(\\s*" + versionToken + "\\s*" |
| | | + versionRegex + "\\s*;\\s*" + aclToken + "\\s*\"(.*)\"\\s*;\\s*" |
| | | + actionRegex + "\\s*\\)"; |
| | | /** |
| | | * Regular expression used to parse the header of the ACI body. The |
| | | * header is version and acl name. |
| | | */ |
| | | public static final String header = |
| | | "\\(\\s*" + versionToken + "\\s*" |
| | | + versionRegex + "\\s*;\\s*" + aclToken + "\\s*\"(.*?)\"\\s*;"; |
| | | |
| | | /** |
| | | * Construct an ACI body from the specified version, name and |
| | | * permission-bind rule pairs. |
| | | * |
| | | * @param verision The version of the ACI. |
| | | * @param name The name of the ACI. |
| | | * @param startPos The start position in the string of the ACI body. |
| | | * @param permBindRulePairs The set of fully parsed permission-bind rule |
| | | * pairs pertaining to this ACI. |
| | | */ |
| | | private AciBody(String verision, String name, int startPos, |
| | | List<PermBindRulePair> permBindRulePairs) { |
| | | this.version=verision; |
| | | this.name=name; |
| | | this.startPos=startPos; |
| | | this.permBindRulePairs=permBindRulePairs; |
| | | } |
| | | |
| | | /** |
| | | * Decode an ACI string representing the ACI body. |
| | | * |
| | | * @param input String representation of the ACI body. |
| | | * @return An AciBody class representing the decoded ACI body string. |
| | | * @throws AciException If the provided string contains errors. |
| | | */ |
| | | public static AciBody decode(String input) |
| | | throws AciException { |
| | | String version=null, name=null; |
| | | int startPos=0; |
| | | List<PermBindRulePair> permBindRulePairs= |
| | | new ArrayList<PermBindRulePair>(); |
| | | Pattern bodyPattern = Pattern.compile(header); |
| | | Matcher bodyMatcher = bodyPattern.matcher(input); |
| | | if(bodyMatcher.find()) { |
| | | startPos=bodyMatcher.start(); |
| | | version = bodyMatcher.group(VERSION); |
| | | if (!version.equalsIgnoreCase(Aci.supportedVersion)) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVAILD_VERSION; |
| | | String message = getMessage(msgID, version); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | name = bodyMatcher.group(NAME); |
| | | } |
| | | Pattern bodyPattern1 = Pattern.compile(actionRegex); |
| | | Matcher bodyMatcher1 = bodyPattern1.matcher(input); |
| | | /* |
| | | * The may be many permission-bind rule pairs. |
| | | */ |
| | | while(bodyMatcher1.find()) { |
| | | String perm=bodyMatcher1.group(PERM); |
| | | String rights=bodyMatcher1.group(RIGHTS); |
| | | String bRule=bodyMatcher1.group(BINDRULE); |
| | | PermBindRulePair pair = PermBindRulePair.decode(perm, rights, bRule); |
| | | permBindRulePairs.add(pair); |
| | | } |
| | | return new AciBody(version, name, startPos, permBindRulePairs); |
| | | } |
| | | |
| | | /** |
| | | * Checks all of the permissions in this body for a specific access type. |
| | | * Need to walk down each permission-bind rule pair and call it's |
| | | * hasAccessType method. |
| | | * |
| | | * @param accessType The access type enumeration to search for. |
| | | * @return True if the access type is found in a permission of |
| | | * a permission bind rule pair. |
| | | */ |
| | | public boolean hasAccessType(EnumAccessType accessType) { |
| | | List<PermBindRulePair>pairs=getPermBindRulePairs(); |
| | | for(PermBindRulePair p : pairs) { |
| | | if(p.hasAccessType(accessType)) |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * Search through each permission bind rule associated with this body and |
| | | * try and match a single right of the specified rights. |
| | | * |
| | | * @param rights The rights that are used in the match. |
| | | * @return True if a one or more right of the specified rights matches |
| | | * a body's permission rights. |
| | | */ |
| | | public boolean hasRights(int rights) { |
| | | List<PermBindRulePair>pairs=getPermBindRulePairs(); |
| | | for(PermBindRulePair p : pairs) { |
| | | if(p.hasRights(rights)) |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * Retrieve the permission-bind rule pairs of this ACI body. |
| | | * |
| | | * @return The permission-bind rule pairs. |
| | | */ |
| | | private List<PermBindRulePair> getPermBindRulePairs() { |
| | | return permBindRulePairs; |
| | | } |
| | | |
| | | /** |
| | | * Get the start position in the ACI string of the ACI body. |
| | | * |
| | | * @return Index into the ACI string of the ACI body. |
| | | */ |
| | | public int getMatcherStartPos() { |
| | | return startPos; |
| | | } |
| | | |
| | | //TODO Evaluate adding support for the "absolute" deny access |
| | | // type precedence operator. |
| | | |
| | | /** |
| | | * Performs an evaluation of the permission-bind rule pairs |
| | | * using the evaluation context. The method walks down |
| | | * each PermBindRulePair object and: |
| | | * |
| | | * 1. Skips a pair if the evaluation context rights don't |
| | | * apply to that ACI. For example, an LDAP search would skip |
| | | * an ACI pair that allows writes. |
| | | * |
| | | * 2. The pair's bind rule is evaluated using the evaluation context. |
| | | * 3. The result of the evaluation is itself evaluated. See comments |
| | | * below in the code. |
| | | * |
| | | * @param evalCtx The evaluation context to evaluate against. |
| | | * @return An enumeration result of the evaluation. |
| | | */ |
| | | public EnumEvalResult evaluate(AciEvalContext evalCtx) { |
| | | EnumEvalResult res=EnumEvalResult.FALSE; |
| | | List<PermBindRulePair>pairs=getPermBindRulePairs(); |
| | | for(PermBindRulePair p : pairs) { |
| | | if(!p.hasRights(evalCtx.getRights())) |
| | | continue; |
| | | res=p.getBindRule().evaluate(evalCtx); |
| | | // The evaluation result could be FAIL. Stop processing and return |
| | | //FAIL. Maybe an internal search failed. |
| | | if((res != EnumEvalResult.TRUE) && |
| | | (res != EnumEvalResult.FALSE)) { |
| | | res=EnumEvalResult.FAIL; |
| | | break; |
| | | //If the access type is DENY and the pair evaluated to TRUE, |
| | | //then stop processing and return TRUE. A deny pair |
| | | //succeeded. |
| | | } else if((p.hasAccessType(EnumAccessType.DENY)) && |
| | | (res == EnumEvalResult.TRUE)) { |
| | | res=EnumEvalResult.TRUE; |
| | | break; |
| | | //An allow access type evaluated TRUE, stop processing |
| | | //and return TRUE. |
| | | } else if((p.hasAccessType(EnumAccessType.ALLOW) && |
| | | (res == EnumEvalResult.TRUE))) { |
| | | res=EnumEvalResult.TRUE; |
| | | break; |
| | | } |
| | | } |
| | | return res; |
| | | } |
| | | } |
| 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.api.ClientConnection; |
| | | import org.opends.server.api.Group; |
| | | import org.opends.server.core.AddOperation; |
| | | import org.opends.server.core.Operation; |
| | | import org.opends.server.extensions.TLSConnectionSecurityProvider; |
| | | import org.opends.server.util.ServerConstants; |
| | | import java.net.InetAddress; |
| | | import java.util.LinkedList; |
| | | |
| | | /** |
| | | * The AciContainer class contains all of the needed information to perform |
| | | * both target match and evaluate an ACI. Target matching is the process |
| | | * of testing if an ACI is applicable to an operation, and evaluation is |
| | | * the actual access evaluation of the ACI. |
| | | */ |
| | | public abstract class AciContainer |
| | | implements AciTargetMatchContext, AciEvalContext { |
| | | |
| | | /* |
| | | * The allow and deny lists. |
| | | */ |
| | | private LinkedList<Aci> denyList, allowList; |
| | | |
| | | /* |
| | | * The attribute type in the resource entry currently being evaluated. |
| | | */ |
| | | private AttributeType attributeType; |
| | | |
| | | /* |
| | | * The attribute type value in the resource entry currently being |
| | | * evaluated. |
| | | */ |
| | | private AttributeValue attributeValue; |
| | | |
| | | /* |
| | | * True if this is the first attribute type in the resource entry being |
| | | * evaluated. |
| | | */ |
| | | private boolean isFirst = false; |
| | | |
| | | /* |
| | | * True if an entry test rule was seen during target matching of an ACI |
| | | * entry. A entry test rule is an ACI with targetattrs target keyword. |
| | | */ |
| | | private boolean isEntryTestRule = false; |
| | | |
| | | /* |
| | | * True if the evaluation of an ACI is from the deny list. |
| | | */ |
| | | private boolean isDenyEval; |
| | | |
| | | /* |
| | | * True if the evaluation is a result of an LDAP add operation. |
| | | */ |
| | | private boolean isAddOp=false; |
| | | |
| | | /* |
| | | * The rights to use in the evaluation of the LDAP operation. |
| | | */ |
| | | private int rights; |
| | | |
| | | /* |
| | | * The entry being evaluated (resource entry). |
| | | */ |
| | | private Entry resourceEntry; |
| | | |
| | | /* |
| | | * The client connection information. |
| | | */ |
| | | private ClientConnection clientConnection; |
| | | |
| | | /* |
| | | * The operation being evaluated. |
| | | */ |
| | | private Operation operation; |
| | | |
| | | /** |
| | | * 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) { |
| | | this.resourceEntry=entry; |
| | | this.operation=operation; |
| | | this.clientConnection=operation.getClientConnection(); |
| | | if(operation instanceof AddOperation) |
| | | this.isAddOp=true; |
| | | this.rights = rights; |
| | | } |
| | | |
| | | /** |
| | | * 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. |
| | | */ |
| | | 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. |
| | | */ |
| | | public void setAllowList(LinkedList<Aci> allows) { |
| | | allowList=allows; |
| | | } |
| | | |
| | | /** |
| | | * Return the current attribute type being evaluated. |
| | | * @return Attribute type being evaluated. |
| | | */ |
| | | public AttributeType getCurrentAttributeType() { |
| | | return attributeType; |
| | | } |
| | | |
| | | /** |
| | | * Return the current attribute type value being evaluated. |
| | | * @return Attribute type value being evaluated. |
| | | */ |
| | | public AttributeValue getCurrentAttributeValue() { |
| | | return attributeValue; |
| | | } |
| | | |
| | | /** |
| | | * Set the attribute type to be evaluated. |
| | | * @param type The attribute type to evaluate. |
| | | */ |
| | | public void setCurrentAttributeType(AttributeType type) { |
| | | attributeType=type; |
| | | } |
| | | |
| | | /** |
| | | * Set the attribute type value to be evaluated. |
| | | * @param value The attribute type value to evaluate. |
| | | */ |
| | | 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. |
| | | */ |
| | | 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. |
| | | */ |
| | | 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. |
| | | */ |
| | | 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) { |
| | | isEntryTestRule=val; |
| | | } |
| | | |
| | | /** |
| | | * Get the entry being evaluated (known as the resource entry). |
| | | * @return The entry being evaluated. |
| | | */ |
| | | public Entry getResourceEntry() { |
| | | return resourceEntry; |
| | | } |
| | | |
| | | /** |
| | | * Get the entry that corresponds to the client DN. |
| | | * @return The client entry. |
| | | */ |
| | | public Entry getClientEntry() { |
| | | return clientConnection.getAuthenticationInfo().getAuthorizationEntry(); |
| | | } |
| | | |
| | | /** |
| | | * Get the deny list of ACIs. |
| | | * @return The deny ACI list. |
| | | */ |
| | | public LinkedList<Aci> getDenyList() { |
| | | return denyList; |
| | | } |
| | | |
| | | /** |
| | | * Get the allow list of ACIs. |
| | | * @return The allow ACI list. |
| | | */ |
| | | 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. |
| | | */ |
| | | public boolean isDenyEval() { |
| | | return isDenyEval; |
| | | } |
| | | |
| | | /** |
| | | * Check is this operation bound anonymously. |
| | | * @return True if the authentication is anonymous. |
| | | */ |
| | | public boolean isAnonymousUser() { |
| | | return !clientConnection.getAuthenticationInfo().isAuthenticated(); |
| | | } |
| | | |
| | | /** |
| | | * Set the deny evaluation flag. |
| | | * @param val True if this evaluation is a deny ACI. |
| | | */ |
| | | public void setDenyEval(boolean val) { |
| | | isDenyEval = val; |
| | | } |
| | | |
| | | /** |
| | | * Returns the client authorization DN known as the client DN. |
| | | * @return The client's authorization DN. |
| | | */ |
| | | public DN getClientDN() { |
| | | return clientConnection.getAuthenticationInfo().getAuthorizationDN(); |
| | | } |
| | | |
| | | /** |
| | | * Get the DN of the entry being evaluated. |
| | | * @return The DN of the entry. |
| | | */ |
| | | 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. |
| | | */ |
| | | 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. |
| | | */ |
| | | 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. |
| | | */ |
| | | public void setRights(int rights) { |
| | | this.rights=rights; |
| | | } |
| | | /** |
| | | * Gets the hostname of the remote client. |
| | | * @return Cannonical hostname of remote client. |
| | | */ |
| | | public String getHostName() { |
| | | return clientConnection.getRemoteAddress().getCanonicalHostName(); |
| | | } |
| | | |
| | | /** |
| | | * Gets the remote client's address information. |
| | | * @return Remote client's address. |
| | | */ |
| | | public InetAddress getRemoteAddress() { |
| | | return clientConnection.getRemoteAddress(); |
| | | } |
| | | |
| | | /** |
| | | * Return true if this is an add operation. |
| | | * @return True if this is an add operation. |
| | | */ |
| | | public boolean isAddOperation() { |
| | | return isAddOp; |
| | | } |
| | | |
| | | /** |
| | | * Tries to determine the authentication information from the connection |
| | | * class. The checks are for simple and SASL, anything else is not a |
| | | * match. If the bind rule needs the SSL client flag then that needs |
| | | * to be set. This code is used by the authmethod bind rule keyword. |
| | | * @param wantSSL True if the bind rule needs the ssl client auth check. |
| | | * @return Return an enumeration containing the authentication method |
| | | * for this connection. |
| | | */ |
| | | public EnumAuthMethod getAuthenticationMethod(boolean wantSSL) { |
| | | EnumAuthMethod method=EnumAuthMethod.AUTHMETHOD_NOMATCH; |
| | | AuthenticationInfo authInfo=clientConnection.getAuthenticationInfo(); |
| | | if(authInfo.isAuthenticated()) { |
| | | if(authInfo.hasAuthenticationType(AuthenticationType.SIMPLE)) |
| | | method=EnumAuthMethod.AUTHMETHOD_SIMPLE; |
| | | else if(authInfo.hasAuthenticationType(AuthenticationType.SASL)) |
| | | method=getSaslAuthenticationMethod(authInfo, wantSSL); |
| | | else |
| | | method=EnumAuthMethod.AUTHMETHOD_NOMATCH; |
| | | } |
| | | return method; |
| | | } |
| | | |
| | | /* |
| | | * TODO This method needs to be tested. |
| | | * TODO Investigate multi-factor authentication. |
| | | * Second, OpenDS is devised so that it could be possible to use |
| | | * multi-factor or step-up authentication, in which the same client |
| | | * has provided multiple forms of credentials, but this method |
| | | * expects only a single authentication type. |
| | | */ |
| | | /** |
| | | * This method attempts to figure out what the SASL method was/is or |
| | | * what the client auth is. |
| | | * @param authInfo The authentication information to use. |
| | | * @param wantSSL The bin drule wants the SSL client auth status. |
| | | * @return An enumeration containing the SASL bind information. |
| | | */ |
| | | private EnumAuthMethod |
| | | getSaslAuthenticationMethod(AuthenticationInfo authInfo, boolean wantSSL) { |
| | | EnumAuthMethod method=EnumAuthMethod.AUTHMETHOD_NOMATCH; |
| | | if(authInfo.hasAuthenticationType(AuthenticationType.SASL)) { |
| | | if(authInfo.hasSASLMechanism(ServerConstants. |
| | | SASL_MECHANISM_DIGEST_MD5)) |
| | | method=EnumAuthMethod.AUTHMETHOD_SASL_MD5; |
| | | else if(authInfo.hasSASLMechanism(ServerConstants. |
| | | SASL_MECHANISM_GSSAPI)) |
| | | method=EnumAuthMethod.AUTHMETHOD_SASL_GSSAPI; |
| | | else if(authInfo.hasSASLMechanism(ServerConstants. |
| | | SASL_MECHANISM_EXTERNAL)) { |
| | | /* |
| | | * The bind rule wants ssl client auth information. Need the |
| | | * security provider to see if the clientAuthPolicy is |
| | | * required. If it is optional, we really can't determine if |
| | | * the client auth. |
| | | */ |
| | | if(wantSSL) { |
| | | String mechName= |
| | | clientConnection.getConnectionSecurityProvider(). |
| | | getSecurityMechanismName(); |
| | | if(mechName.equalsIgnoreCase("TLS")) { |
| | | TLSConnectionSecurityProvider tlsProv= |
| | | (TLSConnectionSecurityProvider)clientConnection. |
| | | getConnectionSecurityProvider(); |
| | | SSLClientAuthPolicy clientAuthPolicy= |
| | | tlsProv.getSSLClientAuthPolicy(); |
| | | if(clientAuthPolicy == SSLClientAuthPolicy.REQUIRED) |
| | | method=EnumAuthMethod.AUTHMETHOD_SSL; |
| | | } else |
| | | method=EnumAuthMethod.AUTHMETHOD_NOMATCH; |
| | | } else { |
| | | method=EnumAuthMethod.AUTHMETHOD_SASL_EXTERNAL; |
| | | } |
| | | } else |
| | | method=EnumAuthMethod.AUTHMETHOD_NOMATCH; |
| | | } |
| | | return method; |
| | | } |
| | | |
| | | /** |
| | | * Convienance 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. |
| | | */ |
| | | public boolean isMemberOf(Group group) { |
| | | boolean ret; |
| | | try { |
| | | ret=clientConnection.isMemberOf(group, operation); |
| | | } catch (DirectoryException ex) { |
| | | ret=false; |
| | | } |
| | | 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; |
| | | |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.api.Group; |
| | | |
| | | import java.net.InetAddress; |
| | | import java.util.LinkedList; |
| | | |
| | | /** |
| | | * Interface that provides a view of the AciContainer that is |
| | | * used by the ACI evaluation code to evaluate an ACI. |
| | | */ |
| | | public interface AciEvalContext |
| | | { |
| | | /** |
| | | * Get client DN. The client DN is the authorization DN. |
| | | * @return The client DN. |
| | | */ |
| | | public DN getClientDN(); |
| | | |
| | | /** |
| | | * Get the client entry. The client entry is the entry that corresponds |
| | | * to the client DN. |
| | | * @return The client entry corresponding to the client DN. |
| | | */ |
| | | public Entry getClientEntry(); |
| | | |
| | | /** |
| | | * Get the resource DN. The resource DN is the DN of the entry being |
| | | * evaluated. |
| | | * @return The resource DN. |
| | | */ |
| | | public DN getResourceDN(); |
| | | |
| | | /** |
| | | * Get the list of deny ACIs. |
| | | * @return The deny ACI list. |
| | | */ |
| | | public LinkedList<Aci> getDenyList(); |
| | | |
| | | /** |
| | | * Get the list allow ACIs. |
| | | * @return The allow ACI list. |
| | | */ |
| | | public LinkedList<Aci> getAllowList(); |
| | | |
| | | /** |
| | | * Set when the deny list is being evaluated. |
| | | * @param v True if deny's are being evaluated. |
| | | */ |
| | | public void setDenyEval(boolean v); |
| | | |
| | | /** |
| | | * Returns true if the deny list is being evaluated. |
| | | * @return True if the deny list is being evaluated. |
| | | */ |
| | | public boolean isDenyEval(); |
| | | |
| | | /** |
| | | * Check if the remote client is bound anonymously. |
| | | * @return True if client is bound anonymously. |
| | | */ |
| | | public boolean isAnonymousUser(); |
| | | |
| | | /** |
| | | * Return the rights set for this container's LDAP operation. |
| | | * @return The rights set for the container's LDAP operation. |
| | | */ |
| | | public int getRights(); |
| | | |
| | | /** |
| | | * Return the entry being evaluated |
| | | * . |
| | | * @return The evaluation entry. |
| | | */ |
| | | public Entry getResourceEntry(); |
| | | |
| | | /** |
| | | * Get the hostname of the bound connection. |
| | | * @return The hostname of the connection. |
| | | */ |
| | | public String getHostName(); |
| | | |
| | | /** |
| | | * Get the authentication method. |
| | | * @param wantSSL The authmethod bind rule needs the SSL client auth |
| | | * status. |
| | | * @return An Enumeration of the auth method bound as. |
| | | */ |
| | | public EnumAuthMethod getAuthenticationMethod(boolean wantSSL); |
| | | |
| | | /** |
| | | * Get the address of the bound connection. |
| | | * @return The address of the bound connection. |
| | | */ |
| | | public InetAddress getRemoteAddress(); |
| | | |
| | | /** |
| | | * Return true if this is an add operation, needed by the userattr |
| | | * USERDN parent inheritance level 0 processing. |
| | | * @return True if this is an add operation. |
| | | */ |
| | | public boolean isAddOperation(); |
| | | |
| | | /** |
| | | * Return true if the operation associated with this evaluation |
| | | * context is a member of the specified group. Calls the |
| | | * ClientConnection.isMemberOf() method, which checks authorization |
| | | * DN membership in the specified group. |
| | | * @param group The group to check membership in. |
| | | * @return True if the authorization DN of the operation is a |
| | | * member of the specified group. |
| | | */ |
| | | public boolean isMemberOf(Group group); |
| | | } |
| 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 static org.opends.server.loggers.Debug.debugConstructor; |
| | | import static org.opends.server.loggers.Debug.debugEnter; |
| | | |
| | | /** |
| | | * The AciException class defines an exception that may be thrown |
| | | * either during ACI syntax verification of an "aci" attribute type value |
| | | * or during evaluation of an LDAP operation using a set of applicable |
| | | * ACIs. |
| | | */ |
| | | public class AciException extends Exception { |
| | | |
| | | /** |
| | | * The fully-qualified name of this class for debugging purposes. |
| | | */ |
| | | private static final String CLASS_NAME = |
| | | "org.opends.server.authorization.dseecompat.AciException"; |
| | | |
| | | /** |
| | | * The serial version identifier required to satisfy the compiler because this |
| | | * class extends <CODE>java.lang.Exception</CODE>, which implements the |
| | | * <CODE>java.io.Serializable</CODE> interface. This value was generated |
| | | * using the <CODE>serialver</CODE> command-line utility included with the |
| | | * Java SDK. |
| | | */ |
| | | private static final long serialVersionUID = -2763328522960628853L; |
| | | |
| | | // The unique message ID for the associated message. |
| | | private int messageID; |
| | | |
| | | /** |
| | | * Constructs a new exception with <code>null</code> as its detail message. |
| | | * The cause is not initialized. Used to break out of a recursive bind rule |
| | | * decode and not print duplicate messages. |
| | | */ |
| | | public AciException() { |
| | | super(); |
| | | } |
| | | |
| | | /** |
| | | * Creates a new ACI exception with the provided message. |
| | | * |
| | | * @param messageID The unique message ID for the provided message. |
| | | * @param message The message to use for this ACI exception. |
| | | */ |
| | | public AciException(int messageID, String message) { |
| | | super(message); |
| | | assert debugConstructor(CLASS_NAME, String.valueOf(messageID), |
| | | String.valueOf(message)); |
| | | this.messageID = messageID; |
| | | } |
| | | |
| | | /** |
| | | * Creates a new ACI exception with the provided message and root |
| | | * cause. |
| | | * |
| | | * @param messageID The unique identifier for the associated message. |
| | | * @param message The message that explains the problem that occurred. |
| | | * @param cause The exception that was caught to trigger this |
| | | * exception. |
| | | */ |
| | | public AciException(int messageID, String message, Throwable cause) { |
| | | super(message, cause); |
| | | |
| | | assert debugConstructor(CLASS_NAME, String.valueOf(message), |
| | | String.valueOf(cause)); |
| | | |
| | | this.messageID = messageID; |
| | | } |
| | | |
| | | /** |
| | | * Retrieves the message ID for this exception. |
| | | * |
| | | * @return The message ID for this exception. |
| | | */ |
| | | public int getMessageID() { |
| | | assert debugEnter(CLASS_NAME, "getMessageID"); |
| | | return messageID; |
| | | } |
| | | } |
| 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.api.AccessControlHandler; |
| | | import static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import org.opends.server.core.*; |
| | | import static org.opends.server.loggers.Debug.debugEnter; |
| | | import static org.opends.server.loggers.Error.logError; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import org.opends.server.types.*; |
| | | import static org.opends.server.util.StaticUtils.toLowerCase; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * The AciHandler class performs the main processing for the |
| | | * dseecompat package. |
| | | */ |
| | | public class AciHandler extends AccessControlHandler |
| | | { |
| | | |
| | | private static final String CLASS_NAME = |
| | | "org.opends.server.authorization.dseecompat.AciHandler"; |
| | | |
| | | /** |
| | | * ACI_ADD is used to set the container rights for a LDAP add operation. |
| | | */ |
| | | public static final int ACI_ADD = 0x0001; |
| | | |
| | | /** |
| | | * ACI_DELETE is used to set the container rights for a LDAP |
| | | * delete operation. |
| | | */ |
| | | public static final int ACI_DELETE = 0x0002; |
| | | |
| | | /** |
| | | * ACI_READ is used to set the container rights for a LDAP |
| | | * search operation. |
| | | */ |
| | | public static final int ACI_READ = 0x0004; |
| | | |
| | | /** |
| | | * ACI_WRITE is used to set the container rights for a LDAP |
| | | * modify operation. |
| | | */ |
| | | public static final int ACI_WRITE = 0x0008; |
| | | |
| | | /** |
| | | * ACI_COMPARE is used to set the container rights for a LDAP |
| | | * compare operation. |
| | | */ |
| | | public static final int ACI_COMPARE = 0x0010; |
| | | |
| | | /** |
| | | * ACI_SEARCH is used to set the container rights a LDAP search operation. |
| | | */ |
| | | public static final int ACI_SEARCH = 0x0020; |
| | | |
| | | /** |
| | | * ACI_SELF is used for the SELFWRITE right. Currently not implemented. |
| | | */ |
| | | public static final int ACI_SELF = 0x0040; |
| | | |
| | | /** |
| | | * ACI_ALL is used to as a mask for all of the above. These |
| | | * six below are not masked by the ACI_ALL. |
| | | */ |
| | | public static final int ACI_ALL = 0x007F; |
| | | |
| | | /** |
| | | * ACI_PROXY is used for the PROXY right. Currently not implemented. |
| | | */ |
| | | public static final int ACI_PROXY = 0x0080; |
| | | |
| | | /** |
| | | * ACI_IMPORT is used to set the container rights for a LDAP |
| | | * modify dn operation. Currently not implemented. |
| | | */ |
| | | public static final int ACI_IMPORT = 0x0100; |
| | | |
| | | /** |
| | | * ACI_EXPORT is used to set the container rights for a LDAP |
| | | * modify dn operation. Currently not implemented. |
| | | */ |
| | | public static final int ACI_EXPORT = 0x0200; |
| | | |
| | | /** |
| | | * ACI_WRITE_ADD and ACI_WRITE_DELETE are used by the LDAP modify |
| | | * operation. They currently don't have much value; but will be needed |
| | | * once the targetattrfilters target and modify dn are implemented. |
| | | */ |
| | | public static final int ACI_WRITE_ADD = 0x800; |
| | | /** |
| | | * See above. |
| | | */ |
| | | public static final int ACI_WRITE_DELETE = 0x400; |
| | | |
| | | /** |
| | | * ACI_NULL is used to set the container rights to all zeros. Used |
| | | * by LDAP modify. |
| | | */ |
| | | public static final int ACI_NULL = 0x0000; |
| | | |
| | | /* |
| | | * The list that holds that ACIs keyed by the DN of the entry |
| | | * holding the ACI. |
| | | */ |
| | | private AciList aciList; |
| | | |
| | | /** |
| | | * Attribute type corresponding to "aci" attribute. |
| | | */ |
| | | public static AttributeType aciType; |
| | | |
| | | /** |
| | | * Constructor that registers the message catalog, creates the ACI list |
| | | * class that manages the ACI list. Instantiates and registers the change |
| | | * notification listener that is used to manage the ACI list on |
| | | * modifications and the backend initialization listener that is used to |
| | | * register/de-register aci attribute types in backends when backends |
| | | * are initialized/finalized. |
| | | */ |
| | | public AciHandler() { |
| | | AciMessages.registerMessages(); |
| | | aciList = new AciList(); |
| | | AciListenerManager aciListenerMgr = |
| | | new AciListenerManager(aciList); |
| | | DirectoryServer.registerChangeNotificationListener(aciListenerMgr); |
| | | DirectoryServer.registerBackendInitializationListener(aciListenerMgr); |
| | | if((aciType = DirectoryServer.getAttributeType("aci")) == null) |
| | | aciType = DirectoryServer.getDefaultAttributeType("aci"); |
| | | } |
| | | |
| | | /* |
| | | * TODO |
| | | * The internal search performed by the searchAcis method will require |
| | | * a presence index on the aci attribute for any database of any significant |
| | | * size. We should probably consider making this index present by default, |
| | | * because if they aren't using the DSEE-compatible implementation then |
| | | * they probably won't have any instances of the aci attribute. |
| | | */ |
| | | /** |
| | | * Checks to see if a LDAP modification is allowed access. |
| | | * |
| | | * @param container The structure containing the LDAP modifications |
| | | * @param operation The operation to check modify privileges on. |
| | | * operation to check and the evaluation context to apply the check against. |
| | | * @param skipAccessCheck True if access checking should be skipped. |
| | | * @return True if access is allowed. |
| | | */ |
| | | private boolean aciCheckMods(AciLDAPOperationContainer container, |
| | | Operation operation, |
| | | boolean skipAccessCheck) { |
| | | Entry resourceEntry=container.getResourceEntry(); |
| | | DN dn=resourceEntry.getDN(); |
| | | List<Modification> modifications=container.getModifications(); |
| | | for(Modification m : modifications) { |
| | | Attribute modAttr=m.getAttribute(); |
| | | AttributeType modType=modAttr.getAttributeType(); |
| | | switch(m.getModificationType()) { |
| | | /* |
| | | * TODO Increment modification type needs to be handled. |
| | | */ |
| | | case DELETE: |
| | | case REPLACE: |
| | | { |
| | | /* |
| | | Check if we have rights to delete all values of |
| | | an attribute type in the resource entry. |
| | | */ |
| | | if(resourceEntry.hasAttribute(modType)) { |
| | | container.setCurrentAttributeType(modType); |
| | | List<Attribute> attrList = |
| | | resourceEntry.getAttribute(modType,null); |
| | | for (Attribute a : attrList) { |
| | | for (AttributeValue v : a.getValues()) { |
| | | container.setCurrentAttributeValue(v); |
| | | container.setRights(ACI_WRITE_DELETE); |
| | | if(!skipAccessCheck && |
| | | !accessAllowed(container)) |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | if(modAttr.hasValue()) { |
| | | boolean checkPrivileges=true; |
| | | for(AttributeValue v : modAttr.getValues()) { |
| | | container.setCurrentAttributeType(modType); |
| | | container.setCurrentAttributeValue(v); |
| | | if((m.getModificationType() == ModificationType.ADD) || |
| | | (m.getModificationType() == ModificationType.REPLACE)) { |
| | | container.setRights(ACI_WRITE_ADD); |
| | | if(!skipAccessCheck && !accessAllowed(container)) |
| | | return false; |
| | | } else if(m.getModificationType() |
| | | == ModificationType.DELETE) { |
| | | container.setRights(ACI_WRITE_DELETE); |
| | | if(!skipAccessCheck && !accessAllowed(container)) |
| | | return false; |
| | | } else |
| | | return false; |
| | | /* |
| | | Check if the modification type has an "aci" attribute type. |
| | | If so, check the syntax of that attribute value. Fail the |
| | | the operation if the syntax check fails. |
| | | */ |
| | | if(modType.equals(aciType)) { |
| | | try { |
| | | /* |
| | | * Check that the operation has modify privileges if |
| | | * it contains an "aci" attribute type. Flip the |
| | | * boolean to false so this check isn't made again |
| | | * if there are several ACI values being added. |
| | | */ |
| | | if(checkPrivileges) { |
| | | if (!operation.getClientConnection(). |
| | | hasPrivilege(Privilege.MODIFY_ACL, operation)) { |
| | | int msgID = |
| | | MSGID_ACI_MODIFY_FAILED_PRIVILEGE; |
| | | String message = getMessage(msgID, |
| | | String.valueOf(container.getResourceDN()), |
| | | String.valueOf(container.getClientDN())); |
| | | logError(ErrorLogCategory.ACCESS_CONTROL, |
| | | ErrorLogSeverity.SEVERE_WARNING, |
| | | message, msgID); |
| | | return false; |
| | | } |
| | | checkPrivileges=false; |
| | | } |
| | | Aci.decode(v.getValue(),dn); |
| | | } catch (AciException ex) { |
| | | int msgID = MSGID_ACI_MODIFY_FAILED_DECODE; |
| | | String message = getMessage(msgID, |
| | | String.valueOf(dn), |
| | | ex.getMessage()); |
| | | logError(ErrorLogCategory.ACCESS_CONTROL, |
| | | ErrorLogSeverity.SEVERE_WARNING, |
| | | message, msgID); |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Performs the test of the deny and allow access lists using the |
| | | * provided evaluation context. The deny list is checked first. |
| | | * |
| | | * @param evalCtx The evaluation context to use. |
| | | * @return True if access is allowed. |
| | | */ |
| | | private boolean testApplicableLists(AciEvalContext evalCtx) { |
| | | EnumEvalResult res=EnumEvalResult.FALSE; |
| | | //First check deny lists |
| | | LinkedList<Aci>denys=evalCtx.getDenyList(); |
| | | 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; |
| | | } |
| | | } |
| | | //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; |
| | | } |
| | | } |
| | | return res.getBoolVal(); |
| | | } |
| | | |
| | | /** |
| | | * Creates the allow and deny ACI lists based on the provided target |
| | | * match context. These lists are stored in the evaluation context. |
| | | * @param candidates List of all possible ACI candidates. |
| | | * @param targetMatchCtx Target matching context to use for testing each |
| | | * ACI. |
| | | */ |
| | | private void createApplicableList(LinkedList<Aci> candidates, |
| | | AciTargetMatchContext targetMatchCtx) |
| | | { |
| | | LinkedList<Aci>denys=new LinkedList<Aci>(); |
| | | LinkedList<Aci>allows=new LinkedList<Aci>(); |
| | | for(Aci aci : candidates) { |
| | | if(Aci.isApplicable(aci, targetMatchCtx)) { |
| | | if (aci.hasAccessType(EnumAccessType.DENY)) { |
| | | denys.add(aci); |
| | | } |
| | | if(aci.hasAccessType(EnumAccessType.ALLOW)) { |
| | | allows.add(aci); |
| | | } |
| | | } |
| | | } |
| | | targetMatchCtx.setAllowList(allows); |
| | | targetMatchCtx.setDenyList(denys); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Check to see if the client entry has BYPASS_ACL privileges |
| | | * for this operation. |
| | | * @param operation The operation to check privileges on. |
| | | * @return True if access checking can be skipped because |
| | | * the operation client connection has BYPASS_ACL privileges. |
| | | */ |
| | | boolean skipAccessCheck(Operation operation) { |
| | | return operation.getClientConnection(). |
| | | hasPrivilege(Privilege.BYPASS_ACL, operation); |
| | | } |
| | | |
| | | /** |
| | | * Check access using the specified container. This container will have all |
| | | * of the information to gather applicable ACIs and perform evaluation on |
| | | * them. |
| | | * |
| | | * @param container An ACI operation container which has all of the |
| | | * information needed to check access. |
| | | * |
| | | * @return True if access is allowed. |
| | | */ |
| | | private boolean accessAllowed(AciContainer container) |
| | | { |
| | | DN dn = container.getResourceEntry().getDN(); |
| | | //For ACI_WRITE_ADD and ACI_WRITE_DELETE set the ACI_WRITE |
| | | //right. |
| | | if(container.hasRights(ACI_WRITE_ADD) || |
| | | container.hasRights(ACI_WRITE_DELETE)) |
| | | container.setRights(container.getRights() | ACI_WRITE); |
| | | /* |
| | | * First get all allowed candidate ACIs. |
| | | */ |
| | | LinkedList<Aci>candidates = aciList.getCandidateAcis(dn); |
| | | /* |
| | | * Create an applicable list of ACIs by target matching each |
| | | * candidate ACI against the container's target match view. |
| | | */ |
| | | createApplicableList(candidates,container); |
| | | /* |
| | | * Lastly, evaluate the applicable list. |
| | | */ |
| | | return(testApplicableLists(container)); |
| | | } |
| | | |
| | | /** |
| | | * Performs an access check against all of the attributes of an entry. |
| | | * The attributes that fail access are removed from the entry. This method |
| | | * performs the processing needed for the filterEntry method processing. |
| | | * |
| | | * @param container The search or compare container which has all of the |
| | | * information needed to filter the attributes for this entry. |
| | | * @return The entry to send back to the client, minus any attribute |
| | | * types that failed access check. |
| | | */ |
| | | private SearchResultEntry |
| | | accessAllowedAttrs(AciLDAPOperationContainer container) { |
| | | Entry e=container.getResourceEntry(); |
| | | List<AttributeType> typeList=getAllAttrs(e); |
| | | for(AttributeType attrType : typeList) { |
| | | container.setCurrentAttributeType(attrType); |
| | | if(!accessAllowed(container)) { |
| | | e.removeAttribute(attrType); |
| | | } |
| | | } |
| | | return container.getSearchResultEntry(); |
| | | } |
| | | |
| | | /** |
| | | * Gathers all of the attribute types in an entry along with the |
| | | * "objectclass" attribute type in a List. The "objectclass" attribute is |
| | | * added to the list first so it is evaluated first. |
| | | * |
| | | * @param e Entry to gather the attributes for. |
| | | * @return List containing the attribute types. |
| | | */ |
| | | private List<AttributeType> getAllAttrs(Entry e) { |
| | | Map<AttributeType,List<Attribute>> attrMap = e.getUserAttributes(); |
| | | List<AttributeType> typeList=new LinkedList<AttributeType>(); |
| | | Attribute attr=e.getObjectClassAttribute(); |
| | | /* |
| | | * When a search is not all attributes returned, the "objectclass" |
| | | * attribute type is missing from the entry. |
| | | */ |
| | | if(attr != null) { |
| | | AttributeType ocType=attr.getAttributeType(); |
| | | typeList.add(ocType); |
| | | } |
| | | typeList.addAll(attrMap.keySet()); |
| | | return typeList; |
| | | } |
| | | |
| | | /* |
| | | * TODO Evaluate performance of this method. |
| | | * TODO Evaluate security concerns of this method. Logic from this method |
| | | * taken almost directly from DS6 implementation. |
| | | * |
| | | * I find the work done in the accessAllowedEntry method, particularly |
| | | * with regard to the entry test evaluation, to be very confusing and |
| | | * potentially pretty inefficient. I'm also concerned that the "return |
| | | * "true" inside the for loop could potentially allow access when it |
| | | * should be denied. |
| | | */ |
| | | /** |
| | | * Check if access is allowed on an entry. Access is checked by iterating |
| | | * through each attribute of an entry, starting with the "objectclass" |
| | | * attribute type. |
| | | * |
| | | * If access is allowed on the entry based on one of it's attribute types, |
| | | * then a possible second access check is performed. This second check is |
| | | * only performed if an entry test ACI was found during the earlier |
| | | * successful access check. An entry test ACI has no "targetattrs" keyword, |
| | | * so allowing access based on an attribute type only would be incorrect. |
| | | * |
| | | * @param container ACI search container containing all of the information |
| | | * needed to check access. |
| | | * |
| | | * @return True if access is allowed. |
| | | */ |
| | | private boolean accessAllowedEntry(AciLDAPOperationContainer container) { |
| | | boolean ret=false; |
| | | //set flag that specifies this is the first attribute evaluated |
| | | //in the entry |
| | | container.setIsFirstAttribute(true); |
| | | List<AttributeType> typeList=getAllAttrs(container.getResourceEntry()); |
| | | for(AttributeType attrType : typeList) { |
| | | container.setCurrentAttributeType(attrType); |
| | | /* |
| | | * Check if access is allowed. If true, then check to see if an |
| | | * entry test rule was found (no targetattrs) during target match |
| | | * evaluation. If such a rule was found, set the current attribute |
| | | * type to "null" and check access again so that rule is applied. |
| | | */ |
| | | if(accessAllowed(container)) { |
| | | if(container.hasEntryTestRule()) { |
| | | container.setCurrentAttributeType(null); |
| | | if(!accessAllowed(container)) { |
| | | /* |
| | | * If we failed because of a deny permission-bind rule, |
| | | * we need to stop and return false. |
| | | */ |
| | | if(container.isDenyEval()) { |
| | | return false; |
| | | } |
| | | /* |
| | | * If we failed because there was no explicit |
| | | * allow rule, then we grant implicit access to the |
| | | * entry. |
| | | */ |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | } |
| | | return ret; |
| | | } |
| | | |
| | | /** |
| | | * Evaluate an entry to be added to see if it has any "aci" |
| | | * attribute type. If it does, examines each "aci" attribute type |
| | | * value for syntax errors. All of the "aci" attribute type values |
| | | * must pass syntax check for the add operation to proceed. Any |
| | | * entry with an "aci" attribute type must have "modify-acl" |
| | | * privileges. |
| | | * |
| | | * @param entry The entry to be examined. |
| | | * @param operation The operation to to check privileges on. |
| | | * @param clientDN The authorization DN. |
| | | * @return True if the entry has no ACI attributes or if all of the "aci" |
| | | * attributes values pass ACI syntax checking. |
| | | */ |
| | | private boolean |
| | | verifySyntax(Entry entry, Operation operation, DN clientDN) { |
| | | if(entry.hasOperationalAttribute(aciType)) { |
| | | /* |
| | | * Check that the operation has "modify-acl" privileges since the |
| | | * entry to be added has an "aci" attribute type. |
| | | */ |
| | | if (!operation.getClientConnection(). |
| | | hasPrivilege(Privilege.MODIFY_ACL, operation)) { |
| | | int msgID = MSGID_ACI_ADD_FAILED_PRIVILEGE; |
| | | String message = getMessage(msgID, |
| | | String.valueOf(entry.getDN()), |
| | | String.valueOf(clientDN)); |
| | | logError(ErrorLogCategory.ACCESS_CONTROL, |
| | | ErrorLogSeverity.SEVERE_WARNING, |
| | | message, msgID); |
| | | return false; |
| | | } |
| | | List<Attribute> attributeList = |
| | | entry.getOperationalAttribute(aciType, null); |
| | | for (Attribute attribute : attributeList) |
| | | { |
| | | for (AttributeValue value : attribute.getValues()) |
| | | { |
| | | try { |
| | | DN dn=entry.getDN(); |
| | | Aci.decode(value.getValue(),dn); |
| | | } catch (AciException ex) { |
| | | int msgID = MSGID_ACI_ADD_FAILED_DECODE; |
| | | String message = getMessage(msgID, |
| | | String.valueOf(entry.getDN()), |
| | | ex.getMessage()); |
| | | logError(ErrorLogCategory.ACCESS_CONTROL, |
| | | ErrorLogSeverity.SEVERE_WARNING, |
| | | message, msgID); |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Check access using the accessAllowed method. The |
| | | * LDAP add, compare, modify and delete operations use this function. |
| | | * The other supported LDAP operations have more specialized checks. |
| | | * @param operationContainer The container containing the information |
| | | * needed to evaluate this operation. |
| | | * @param operation The operation being evaluated. |
| | | * @return True if this operation is allowed access. |
| | | */ |
| | | private boolean isAllowed(AciLDAPOperationContainer operationContainer, |
| | | Operation operation) { |
| | | return skipAccessCheck(operation) || accessAllowed(operationContainer); |
| | | } |
| | | |
| | | /** |
| | | * Check access on add operations. |
| | | * |
| | | * @param operation The add operation to check access on. |
| | | * @return True if access is allowed. |
| | | */ |
| | | public boolean isAllowed(AddOperation operation) { |
| | | assert debugEnter(CLASS_NAME, "isAllowed"); |
| | | AciLDAPOperationContainer operationContainer = |
| | | new AciLDAPOperationContainer(operation, ACI_ADD); |
| | | boolean ret=isAllowed(operationContainer,operation); |
| | | //LDAP add needs a verify ACI syntax step in case any |
| | | //"aci" attribute types are being added. |
| | | if(ret) |
| | | ret=verifySyntax(operation.getEntryToAdd(), operation, |
| | | operationContainer.getClientDN()); |
| | | return ret; |
| | | } |
| | | |
| | | /** |
| | | * Check access on compare operations. Note that the attribute |
| | | * type is unavailable at this time, so this method partially |
| | | * parses the raw attribute string to get the base attribute |
| | | * type. Options are ignored. |
| | | * |
| | | * @param operation The compare operation to check access on. |
| | | * @return True if access is allowed. |
| | | */ |
| | | public boolean isAllowed(CompareOperation operation) { |
| | | assert debugEnter(CLASS_NAME, "isAllowed"); |
| | | |
| | | AciLDAPOperationContainer operationContainer = |
| | | new AciLDAPOperationContainer(operation, ACI_COMPARE); |
| | | String baseName; |
| | | String rawAttributeType=operation.getRawAttributeType(); |
| | | int semicolonPosition=rawAttributeType.indexOf(';'); |
| | | if (semicolonPosition > 0) |
| | | baseName = |
| | | toLowerCase(rawAttributeType.substring(0, semicolonPosition)); |
| | | else |
| | | baseName = toLowerCase(rawAttributeType); |
| | | AttributeType attributeType; |
| | | if((attributeType = |
| | | DirectoryServer.getAttributeType(baseName)) == null) |
| | | attributeType = DirectoryServer.getDefaultAttributeType(baseName); |
| | | AttributeValue attributeValue = |
| | | new AttributeValue(attributeType, operation.getAssertionValue()); |
| | | operationContainer.setCurrentAttributeType(attributeType); |
| | | operationContainer.setCurrentAttributeValue(attributeValue); |
| | | return isAllowed(operationContainer, operation); |
| | | } |
| | | |
| | | /** |
| | | * Check access on delete operations. |
| | | * |
| | | * @param operation The delete operation to check access on. |
| | | * @return True if access is allowed. |
| | | */ |
| | | public boolean isAllowed(DeleteOperation operation) { |
| | | assert debugEnter(CLASS_NAME, "isAllowed"); |
| | | AciLDAPOperationContainer operationContainer= |
| | | new AciLDAPOperationContainer(operation, ACI_DELETE); |
| | | return isAllowed(operationContainer, operation); |
| | | } |
| | | |
| | | /** |
| | | * Check access on modify operations. |
| | | * |
| | | * @param operation The modify operation to check access on. |
| | | * @return True if access is allowed. |
| | | */ |
| | | |
| | | public boolean isAllowed(ModifyOperation operation) { |
| | | assert debugEnter(CLASS_NAME, "isAllowed"); |
| | | AciLDAPOperationContainer operationContainer= |
| | | new AciLDAPOperationContainer(operation, ACI_NULL); |
| | | return aciCheckMods(operationContainer, operation, |
| | | skipAccessCheck(operation)); |
| | | } |
| | | |
| | | |
| | | /* |
| | | * TODO Add access testing of the filter against the entry. This was |
| | | * brought up in the first code review. |
| | | * |
| | | * The static block that creates the arrays of EnumRight objects needs to |
| | | * be documented to explain what they are. Also, I still disagree with |
| | | * the interpretation that the READ right is all that is necessary to |
| | | * perform either search or compare operations. That definitely goes |
| | | * against the documentation, which states that READ applies only to |
| | | * the search operation, and that users must have both SEARCH and READ |
| | | * in order to access the results. |
| | | */ |
| | | /** |
| | | * Checks access on a search operation. |
| | | * @param operation The search operation class containing information to |
| | | * check the access on. |
| | | * @param entry The entry to evaluate access. |
| | | * @return True if access is allowed. |
| | | */ |
| | | public boolean |
| | | maySend(SearchOperation operation, SearchResultEntry entry) { |
| | | assert debugEnter(CLASS_NAME, "maySend"); |
| | | AciLDAPOperationContainer operationContainer = |
| | | new AciLDAPOperationContainer(operation, |
| | | (ACI_READ | ACI_SEARCH), entry); |
| | | return skipAccessCheck(operation) || |
| | | accessAllowedEntry(operationContainer); |
| | | } |
| | | |
| | | /* |
| | | * TODO Rename this method. Needs to be changed in SearchOperation. |
| | | * |
| | | * I find the name of the filterEntry method to be misleading because |
| | | * it works on a search operation but has nothing to do with the search |
| | | * filter. Something like "removeDisallowedAttributes" would be clearer. |
| | | */ |
| | | /** |
| | | * Checks access on each attribute in an entry. It removes those attributes |
| | | * that fail access check. |
| | | * |
| | | * @param operation The search operation class containing information to |
| | | * check access on. |
| | | * @param entry The entry containing the attributes. |
| | | * @return The entry to return minus filtered attributes. |
| | | */ |
| | | public SearchResultEntry filterEntry(SearchOperation operation, |
| | | SearchResultEntry entry) { |
| | | |
| | | assert debugEnter(CLASS_NAME, "filterEntry"); |
| | | AciLDAPOperationContainer operationContainer = |
| | | new AciLDAPOperationContainer(operation, |
| | | (ACI_READ | ACI_SEARCH), entry); |
| | | SearchResultEntry returnEntry; |
| | | if(!skipAccessCheck(operation)) { |
| | | returnEntry=accessAllowedAttrs(operationContainer); |
| | | } else |
| | | returnEntry=entry; |
| | | return returnEntry; |
| | | } |
| | | |
| | | //Planned to be implemented methods |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean maySend(SearchOperation operation, |
| | | SearchResultReference reference) { |
| | | assert debugEnter(CLASS_NAME, "maySend"); |
| | | //TODO: Planned to be implemented. |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isAllowed(ModifyDNOperation modifyDNOperation) { |
| | | assert debugEnter(CLASS_NAME, "isAllowed"); |
| | | // TODO: Planned to be implemented. |
| | | return true; |
| | | } |
| | | |
| | | //Not planned to be implemented methods. |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isAllowed(BindOperation bindOperation) { |
| | | assert debugEnter(CLASS_NAME, "isAllowed"); |
| | | //Not planned to be implemented. |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isAllowed(ExtendedOperation extendedOperation) { |
| | | assert debugEnter(CLASS_NAME, "isAllowed"); |
| | | //Not planned to be implemented. |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isAllowed(SearchOperation searchOperation) { |
| | | assert debugEnter(CLASS_NAME, "isAllowed"); |
| | | //Not planned to be implemented. |
| | | return true; |
| | | } |
| | | } |
| 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 java.util.List; |
| | | |
| | | import org.opends.server.core.AddOperation; |
| | | import org.opends.server.core.CompareOperation; |
| | | import org.opends.server.core.DeleteOperation; |
| | | import org.opends.server.core.ModifyOperation; |
| | | import org.opends.server.core.SearchOperation; |
| | | import org.opends.server.types.Modification; |
| | | import org.opends.server.types.SearchResultEntry; |
| | | |
| | | /** |
| | | * The AciLDAPOperationContainer is an AciContainer |
| | | * extended class that wraps each LDAP operation being |
| | | * evaluated or tested for target matched of an ACI. |
| | | */ |
| | | public class AciLDAPOperationContainer extends AciContainer { |
| | | |
| | | /** |
| | | * The entry to be returned if this is a LDAP search. |
| | | */ |
| | | private SearchResultEntry searchEntry; |
| | | |
| | | /** |
| | | * The list of modifications if this operation is a LDAP |
| | | * modify. |
| | | */ |
| | | private List<Modification> modifications; |
| | | /** |
| | | * Constructor interface for the compare operation. |
| | | * @param operation The compare operation to evaluate. |
| | | * @param rights The rights of a compare operation. |
| | | */ |
| | | public AciLDAPOperationContainer(CompareOperation operation, int rights) { |
| | | super(operation, rights, operation.getEntryToCompare()); |
| | | } |
| | | |
| | | /** |
| | | * Constructor interface for the add operation. |
| | | * @param operation The add operation to evaluate. |
| | | * @param rights The rights of an add operation. |
| | | */ |
| | | public AciLDAPOperationContainer(AddOperation operation, int rights) { |
| | | super(operation, rights, operation.getEntryToAdd()); |
| | | } |
| | | |
| | | /** |
| | | * Constructor interface for the delete operation. |
| | | * @param operation The add operation to evaluate. |
| | | * @param rights The rights of a delete operation. |
| | | */ |
| | | public AciLDAPOperationContainer(DeleteOperation operation, int rights) { |
| | | super(operation, rights, operation.getEntryToDelete()); |
| | | } |
| | | |
| | | /** |
| | | * Constructor interface for the modify operation. |
| | | * @param rights The rights of modify operation. |
| | | * @param operation The add operation to evaluate. |
| | | */ |
| | | public AciLDAPOperationContainer(ModifyOperation operation, int rights) { |
| | | super(operation, rights, operation.getCurrentEntry()); |
| | | this.modifications=operation.getModifications(); |
| | | } |
| | | |
| | | /** |
| | | * Constructor interface for the LDAP search operation. |
| | | * @param operation The search operation. |
| | | * @param rights The rights of a search operation. |
| | | * @param entry The entry to be evaluated for this search. |
| | | */ |
| | | public AciLDAPOperationContainer(SearchOperation operation, int rights, |
| | | SearchResultEntry entry) { |
| | | super(operation, rights, entry); |
| | | this.searchEntry = entry; |
| | | } |
| | | |
| | | /** |
| | | * Retrieve the search result entry of the search operation. |
| | | * @return The search result entry. |
| | | */ |
| | | public SearchResultEntry getSearchResultEntry() { |
| | | return this.searchEntry; |
| | | } |
| | | |
| | | /** Retrieve the list of modifications if this is a LDAP modify. |
| | | * @return The list of LDAP modifications to made on the resource entry. |
| | | */ |
| | | public List<Modification> getModifications() { |
| | | return modifications; |
| | | } |
| | | } |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.loggers.Error.logError; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | import java.util.concurrent.locks.Lock; |
| | | import java.util.concurrent.locks.ReentrantReadWriteLock; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeValue; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.ErrorLogCategory; |
| | | import org.opends.server.types.ErrorLogSeverity; |
| | | import org.opends.server.api.Backend; |
| | | |
| | | /** |
| | | * The AciList class performs caching of the ACI attribute values |
| | | * using the entry DN as the key. |
| | | */ |
| | | public class AciList { |
| | | /* |
| | | * TODO Change linked list implementation as suggested below. |
| | | * I would strongly recommend that you change aciList to be |
| | | * LinkedHashMap<DN,List<Aci>> or LinkedHashMap<DN,Aci[]> rather than |
| | | * LinkedHashMap<String,Aci>. It looks like there are some costly |
| | | * string->DN and even string->DN->string conversions. Further, the very |
| | | * hackish way that the linked-list is currently maintained is very |
| | | * ugly and potentially error-prone. |
| | | */ |
| | | private LinkedHashMap<DN, Aci> aciList = |
| | | new LinkedHashMap<DN, Aci>(); |
| | | /* |
| | | * TODO Evaluate making this class lock-free. |
| | | * I would definitely try to make this a lock-free class if at all |
| | | * possible. Read locks aren't free to acquire, since they still require |
| | | * an exclusive lock at some point. If possible, you should use a |
| | | * copy-on-write structure so that you only incur penalties for changing |
| | | * the ACI list (which should be a rare event) and there is no need for |
| | | * any kind of locking at all for read operations. |
| | | */ |
| | | private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); |
| | | private final Lock aciReadLock = rwl.readLock(); |
| | | private final Lock aciWriteLock = rwl.writeLock(); |
| | | |
| | | /* |
| | | * TODO Add support global ACIs in config.ldif. |
| | | * |
| | | */ |
| | | /** |
| | | * Using the base DN, return a list of ACIs that are candidates for |
| | | * evaluation by walking up from the base DN towards the root of the |
| | | * DIT gathering ACIs on parents. |
| | | * |
| | | * @param baseDN The DN to check. |
| | | * @return A list of candidate ACIs that might be applicable. |
| | | */ |
| | | public LinkedList<Aci> getCandidateAcis(DN baseDN) { |
| | | LinkedList<Aci> candidates = new LinkedList<Aci>(); |
| | | if(baseDN == null) |
| | | return candidates; |
| | | try { |
| | | aciReadLock.lock(); |
| | | while(baseDN != null) { |
| | | Aci aci = aciList.get(baseDN); |
| | | if (aci != null) |
| | | { |
| | | while (aci != null) |
| | | { |
| | | candidates.add(aci); |
| | | aci = aci.next; |
| | | } |
| | | } |
| | | if(baseDN.isNullDN()) |
| | | break; |
| | | DN parentDN=baseDN.getParent(); |
| | | if(parentDN == null) |
| | | baseDN=DN.nullDN(); |
| | | else |
| | | baseDN=parentDN; |
| | | } |
| | | } finally { |
| | | aciReadLock.unlock(); |
| | | } |
| | | return candidates; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Add all of an entries ACI attribute values to the ACI list. This |
| | | * method locks/unlocks the list. |
| | | * @param entry The entry containing the "aci" attribute values.\ |
| | | * @return The number of valid ACI attribute values added to the ACI list. |
| | | */ |
| | | public int addAci(Entry entry) { |
| | | int validAcis=0; |
| | | DN dn=entry.getDN(); |
| | | List<Attribute> attributeList = |
| | | entry.getOperationalAttribute(AciHandler.aciType); |
| | | try { |
| | | aciWriteLock.lock(); |
| | | validAcis=addAciAttributeListNoLock(dn, attributeList); |
| | | } finally { |
| | | aciWriteLock.unlock(); |
| | | } |
| | | return validAcis; |
| | | } |
| | | |
| | | /** |
| | | * Add "aci" attribute type values to the ACI list. There is a chance |
| | | * that an ACI will throw an exception if it has an invalid syntax. |
| | | * If that happens a message will be logged and the ACI skipped. |
| | | * @param dn The DN to use a the key in the ACI list. |
| | | * @param attributeList List of attributes contain the "aci" attribute |
| | | * values. |
| | | * @return The number of valid "aci" attribute types added to the ACI list. |
| | | */ |
| | | private int addAciAttributeListNoLock(DN dn, |
| | | List<Attribute> attributeList) { |
| | | int validAcis=0; |
| | | for (Attribute attribute : attributeList) { |
| | | for (AttributeValue value : attribute.getValues()) { |
| | | try { |
| | | Aci aci= Aci.decode(value.getValue(),dn); |
| | | addAci(dn, aci); |
| | | validAcis++; |
| | | } catch (AciException ex) { |
| | | /* An illegal ACI might have been loaded |
| | | * during import and is failing at ACI handler |
| | | * initialization time. Log a message and continue |
| | | * processing. ACIs added via LDAP add have their |
| | | * syntax checked before adding and should never |
| | | * hit this code. |
| | | */ |
| | | int msgID = MSGID_ACI_ADD_LIST_FAILED_DECODE; |
| | | String message = getMessage(msgID, |
| | | ex.getMessage()); |
| | | logError(ErrorLogCategory.ACCESS_CONTROL, |
| | | ErrorLogSeverity.SEVERE_WARNING, |
| | | message, msgID); |
| | | } |
| | | } |
| | | } |
| | | return validAcis; |
| | | } |
| | | |
| | | /** |
| | | * Remove all of the ACIs related to the old entry and then add all of the |
| | | * ACIs related to the new entry. This method locks/unlocks the list. |
| | | * @param oldEntry The old entry maybe containing old "aci" attribute |
| | | * values. |
| | | * @param newEntry The new entry maybe containing new "aci" attribute |
| | | * values. |
| | | */ |
| | | public void modAciOldNewEntry(Entry oldEntry, Entry newEntry) { |
| | | if((oldEntry.hasOperationalAttribute(AciHandler.aciType)) || |
| | | (newEntry.hasOperationalAttribute(AciHandler.aciType))) { |
| | | try { |
| | | aciWriteLock.lock(); |
| | | aciList.remove(oldEntry.getDN()); |
| | | List<Attribute> attributeList = |
| | | newEntry.getOperationalAttribute(AciHandler.aciType, null); |
| | | addAciAttributeListNoLock(newEntry.getDN(),attributeList); |
| | | } finally { |
| | | aciWriteLock.unlock(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Add an ACI using the DN as a key. If the DN already |
| | | * has ACI(s) on the list, then the new ACI is added to the |
| | | * end of the linked list. |
| | | * @param dn The DN to use as the key. |
| | | * @param aci The ACI to add to the list. |
| | | */ |
| | | public void addAci(DN dn, Aci aci) { |
| | | if(aciList.containsKey(dn)) { |
| | | Aci tmpAci = aciList.get(dn); |
| | | while(tmpAci.next != null) |
| | | tmpAci=tmpAci.next; |
| | | tmpAci.next=aci; |
| | | } else |
| | | aciList.put(dn, aci); |
| | | } |
| | | |
| | | /** |
| | | * Remove ACIs related to an entry. |
| | | * @param entry The entry to be removed. |
| | | * @return True if the ACI set was deleted. |
| | | */ |
| | | public boolean removeAci(Entry entry) { |
| | | boolean deleted = false; |
| | | try { |
| | | aciWriteLock.lock(); |
| | | if (aciList.remove(entry.getDN()) != null) |
| | | deleted = true; |
| | | } finally { |
| | | aciWriteLock.unlock(); |
| | | } |
| | | return deleted; |
| | | } |
| | | |
| | | /** |
| | | * Remove all ACIs related to a backend. |
| | | * @param backend The backend to check if each DN is handled by that |
| | | * backend. |
| | | */ |
| | | public void removeAci (Backend backend) { |
| | | try { |
| | | aciWriteLock.lock(); |
| | | Set<DN> keys=aciList.keySet(); |
| | | for(DN dn : keys) { |
| | | if (backend.handlesEntry(dn)) |
| | | aciList.remove(dn); |
| | | } |
| | | } finally { |
| | | aciWriteLock.unlock(); |
| | | } |
| | | } |
| | | } |
| 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.api.ChangeNotificationListener; |
| | | import org.opends.server.api.BackendInitializationListener; |
| | | import org.opends.server.api.Backend; |
| | | import org.opends.server.types.*; |
| | | import org.opends.server.types.operation.PostResponseAddOperation; |
| | | import org.opends.server.types.operation.PostResponseDeleteOperation; |
| | | import org.opends.server.types.operation.PostResponseModifyOperation; |
| | | import org.opends.server.types.operation.PostResponseModifyDNOperation; |
| | | import org.opends.server.protocols.internal.InternalClientConnection; |
| | | import org.opends.server.protocols.internal.InternalSearchOperation; |
| | | import static org.opends.server.loggers.Debug.debugException; |
| | | import static org.opends.server.loggers.Error.logError; |
| | | import static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | |
| | | import java.util.LinkedHashSet; |
| | | |
| | | /** |
| | | * The AciListenerManager updates an ACI list after each |
| | | * modification operation. Also, updates ACI list when backends are initialized |
| | | * and finalized. |
| | | */ |
| | | public class AciListenerManager |
| | | implements ChangeNotificationListener, BackendInitializationListener { |
| | | |
| | | /** |
| | | * The fully-qualified name of this class for debugging purposes. |
| | | */ |
| | | private static final String CLASS_NAME = |
| | | "org.opends.server.core.AciListenerManager"; |
| | | |
| | | private AciList aciList; |
| | | /* |
| | | * Search filter used in context search for "aci" attribute types. |
| | | */ |
| | | private static SearchFilter aciFilter; |
| | | /** |
| | | * The aci attribute type is operational so we need to specify it to be |
| | | * returned. |
| | | */ |
| | | private static LinkedHashSet<String> attrs = new LinkedHashSet<String>(); |
| | | |
| | | static { |
| | | /* |
| | | * Set up the filter used to search private and public contexts. |
| | | */ |
| | | try { |
| | | aciFilter=SearchFilter.createFilterFromString("(aci=*)"); |
| | | } catch (DirectoryException ex) { |
| | | //TODO should never happen, error message? |
| | | } |
| | | attrs.add("aci"); |
| | | } |
| | | /** |
| | | * Save the list created by the AciHandler routine. |
| | | * @param aciList The list object created and loaded by the handler. |
| | | */ |
| | | public AciListenerManager(AciList aciList) { |
| | | this.aciList=aciList; |
| | | } |
| | | |
| | | /** |
| | | * A delete operation succeeded. Remove any ACIs associated with the |
| | | * entry deleted. |
| | | * @param deleteOperation The delete operation. |
| | | * @param entry The entry being deleted. |
| | | */ |
| | | public void handleDeleteOperation(PostResponseDeleteOperation |
| | | deleteOperation, Entry entry) { |
| | | if(entry.hasOperationalAttribute(AciHandler.aciType)) { |
| | | aciList.removeAci(entry); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * An Add operation succeeded. Add any ACIs associated with the |
| | | * entry being added. |
| | | * @param addOperation The add operation. |
| | | * @param entry The entry being added. |
| | | */ |
| | | public void handleAddOperation(PostResponseAddOperation addOperation, |
| | | Entry entry) { |
| | | if(entry.hasOperationalAttribute(AciHandler.aciType)) |
| | | { |
| | | aciList.addAci(entry); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * A modify operation succeeded. Adjust the ACIs by removing |
| | | * ACIs based on the oldEntry and then adding ACIs based on the new |
| | | * entry. |
| | | * @param modOperation the modify operation. |
| | | * @param oldEntry The old entry to examine. |
| | | * @param newEntry The new entry to examine. |
| | | */ |
| | | public void handleModifyOperation(PostResponseModifyOperation modOperation, |
| | | Entry oldEntry, Entry newEntry) |
| | | { |
| | | aciList.modAciOldNewEntry(oldEntry, newEntry); |
| | | } |
| | | |
| | | /** |
| | | * Not implemented. |
| | | * @param modifyDNOperation The LDAP modify DN operation. |
| | | * @param oldEntry The old entry. |
| | | * @param newEntry The new entry. |
| | | */ |
| | | public void handleModifyDNOperation( |
| | | PostResponseModifyDNOperation modifyDNOperation, |
| | | Entry oldEntry, Entry newEntry) |
| | | { |
| | | /* |
| | | * TODO Not yet implemented. |
| | | */ |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} In this case, the server will search the backend to find |
| | | * all aci attribute type values that it may contain and add them to the |
| | | * ACI list. |
| | | */ |
| | | public void performBackendInitializationProcessing(Backend backend) { |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | for (DN baseDN : backend.getBaseDNs()) { |
| | | try { |
| | | if (! backend.entryExists(baseDN)) { |
| | | continue; |
| | | } |
| | | } catch (Exception e) { |
| | | assert debugException(CLASS_NAME, |
| | | "performBackendInitializationProcessing", e); |
| | | //TODO log message |
| | | continue; |
| | | } |
| | | InternalSearchOperation internalSearch = |
| | | new InternalSearchOperation(conn, |
| | | InternalClientConnection.nextOperationID(), |
| | | InternalClientConnection.nextMessageID(), |
| | | null, baseDN, SearchScope.WHOLE_SUBTREE, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, |
| | | 0, 0, false, aciFilter, attrs, null); |
| | | try |
| | | { |
| | | backend.search(internalSearch); |
| | | } catch (Exception e) { |
| | | assert debugException(CLASS_NAME, |
| | | "performBackendInitializationProcessing", e); |
| | | //TODO log message |
| | | continue; |
| | | } |
| | | if(internalSearch.getSearchEntries().isEmpty()) { |
| | | int msgID = MSGID_ACI_ADD_LIST_NO_ACIS; |
| | | String message = getMessage(msgID, String.valueOf(baseDN)); |
| | | logError(ErrorLogCategory.ACCESS_CONTROL, |
| | | ErrorLogSeverity.NOTICE, message, msgID); |
| | | } else { |
| | | int validAcis=0; |
| | | for (SearchResultEntry entry : |
| | | internalSearch.getSearchEntries()) { |
| | | validAcis += aciList.addAci(entry); |
| | | } |
| | | int msgID = MSGID_ACI_ADD_LIST_ACIS; |
| | | String message = getMessage(msgID, Integer.toString(validAcis), |
| | | String.valueOf(baseDN)); |
| | | logError(ErrorLogCategory.ACCESS_CONTROL, |
| | | ErrorLogSeverity.NOTICE, |
| | | message, msgID); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} In this case, the server will remove all aci attribute |
| | | * type values associated with entries in the provided backend. |
| | | */ |
| | | public void performBackendFinalizationProcessing(Backend backend) { |
| | | aciList.removeAci(backend); |
| | | } |
| | | } |
| 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 static org.opends.server.messages.MessageHandler.*; |
| | | |
| | | /** |
| | | * The AciMessages class defines the set of message IDs and default format |
| | | * strings for messages associated with the dseecompat access control |
| | | * implementation. |
| | | */ |
| | | public class AciMessages { |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value cannot be parsed because it failed the non-specific regular |
| | | * expression check during the initial ACI decode process. This takes one |
| | | * argument, which is the string representation of the "aci" attribute |
| | | * type value. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_GENERAL_PARSE_FAILED = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 1; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of an invalid version string. This |
| | | * takes one argument, which is the version string parsed from the |
| | | * "aci" attribute type value. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVAILD_VERSION = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 2; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of an invalid access type string. This |
| | | * takes one argument, which is the access type string parsed from the |
| | | * "aci" attribute type value. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_ACCESS_TYPE_VERSION = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 3; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of an invalid rights string. This |
| | | * takes one argument, which is the rights string parsed from the |
| | | * "aci" attribute type value. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_RIGHTS_SYNTAX = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 4; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of an invalid rights keyword. This |
| | | * takes one argument, which is the rights keyword string parsed from the |
| | | * rights string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_RIGHTS_KEYWORD = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 5; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an ACI bind rule |
| | | * value failed parsing because it starts with an open parenthesis, |
| | | * but does not contain a matching close parenthesis. This takes one |
| | | * argument, which is the bind rule string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_BIND_RULE_MISSING_CLOSE_PAREN = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_MILD_ERROR | 6; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an ACI bind rule |
| | | * value failed parsing because it is an invalid bind rule syntax. This |
| | | * takes one argument, which is the bind rule string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_BIND_RULE_SYNTAX = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_MILD_ERROR | 7; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of an invalid bind rule keyword. This |
| | | * takes one argument, which is the bind rule keyword string parsed from |
| | | * the bind rule string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 8; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of an invalid bind rule operator. This |
| | | * takes one argument, which is the bind rule operator string parsed |
| | | * from the bind rule string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_BIND_RULE_OPERATOR = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 9; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of a missing bind rule expression |
| | | * string. This takes one argument, which is the bind rule string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_MISSING_BIND_RULE_EXPRESSION = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 10; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of an invalid bind rule boolean |
| | | * operator. This takes one argument, which is the bind rule boolean |
| | | * operator string parsed from the bind rule string. |
| | | */ |
| | | public static |
| | | final int MSGID_ACI_SYNTAX_INVALID_BIND_RULE_BOOLEAN_OPERATOR = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 11; |
| | | |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of an invalid bind rule keyword, |
| | | * keyword operation combination. This takes two arguments, which are the |
| | | * bind rule keyword string and the bind rule keyword operator parsed from |
| | | * the bind rule string. |
| | | */ |
| | | public static |
| | | final int MSGID_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD_OPERATOR_COMBO = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 12; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule userdn LDAP URL failed |
| | | * to decode. This takes one argument the message from the LDAP |
| | | * URL decode DirectoryException. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_USERDN_URL = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 13; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule roledn expression failed |
| | | * to parse. This takes one argument, which is the roledn expression |
| | | * string parsed from the bind rule string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_ROLEDN_EXPRESSION = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 14; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule roledn LDAP URL failed |
| | | * to decode. This takes one argument the message from the LDAP |
| | | * URL decode DirectoryException. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_ROLEDN_URL = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 15; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule groupdn expression failed |
| | | * to parse. This takes one argument, which is the groupdn expression |
| | | * string parsed from the bind rule string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_GROUPDN_EXPRESSION = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 16; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule groupdn LDAP URL failed |
| | | * to decode. This takes one argument the message from the LDAP |
| | | * URL decode DirectoryException. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_GROUPDN_URL = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 17; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule ip keyword expression |
| | | * network mask value did not match the expression network address value. |
| | | * For example, the ACI has a IPV6 network mask; but the internet |
| | | * address part is IPV4. This takes two arguments, which are the |
| | | * bind rule ip netmask string and the bind rule ip inet address |
| | | * parsed from the bind rule string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_ADDRESS_FAMILY_MISMATCH = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 18; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule ip keyword expression |
| | | * failed to parse because the number of bits specified to match the |
| | | * network was not valid for the inet address specified. This takes |
| | | * two arguments, which an string specifying the address type |
| | | * (inet6address, inet4address) and an error message. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_NETWORK_BIT_MATCH = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 19; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule ip expression failed |
| | | * to decode. This takes one argument, the message from the |
| | | * thrown exception. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_IP_CRITERIA_DECODE = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 20; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule ip expression failed |
| | | * to parse. This takes one argument, which is the ip expression |
| | | * string parsed from the bind rule string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_IP_EXPRESSION = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 21; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule dns expression failed |
| | | * to parse. This takes one argument, which is the dns expression |
| | | * string parsed from the bind rule string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_DNS_EXPRESSION = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 22; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule dns expression failed |
| | | * to parse because a wild-card was not in the leftmost position. |
| | | * This takes one argument, which is the dns expression string parsed |
| | | * from the bind rule string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_DNS_WILDCARD = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 23; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule dayofweek expression failed |
| | | * to parse. This takes one argument, which is the dayofweek expression |
| | | * string parsed from the bind rule string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_DAYOFWEEK = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING |24; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule timeofday expression failed |
| | | * to parse. This takes one argument, which is the timeofday expression |
| | | * string parsed from the bind rule string. |
| | | */ |
| | | |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_TIMEOFDAY = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING |25; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule timeofday expression failed |
| | | * to parse because the timeofday was not in a valid range. This takes one |
| | | * argument, which is the timeofday expression string parsed from the |
| | | * bind rule string. |
| | | */ |
| | | |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_TIMEOFDAY_RANGE = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING |26; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule authmethod expression failed |
| | | * to parse. This takes one argument, which is the authmethod expression |
| | | * string parsed from the bind rule string. |
| | | */ |
| | | |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_AUTHMETHOD_EXPRESSION = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING |27; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule userattr expression failed |
| | | * to decode. This takes one argument, the message from the |
| | | * thrown exception. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_USERATTR_EXPRESSION = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 28; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule userattr expression value |
| | | * is not supported. This takes one argument, which is the userattr |
| | | * expression string parsed from the bind rule string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_USERATTR_KEYWORD = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 29; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule userattr expression |
| | | * inheritance pattern did not parse. This takes one argument, which |
| | | * is the userattr expression inheritance pattern string parsed |
| | | * from the bind rule string. |
| | | */ |
| | | public static |
| | | final int MSGID_ACI_SYNTAX_INVALID_USERATTR_INHERITANCE_PATTERN = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 30; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule userattr expression |
| | | * inheritance level exceeded the max value. This takes two arguments, |
| | | * which are the userattr expression inheritance pattern string parsed |
| | | * from the bind rule string and the max leval value. |
| | | */ |
| | | public static |
| | | final int MSGID_ACI_SYNTAX_MAX_USERATTR_INHERITANCE_LEVEL_EXCEEDED = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 31; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule userattr expression |
| | | * inheritance level was non-numeric. This takes one argument, |
| | | * which is the userattr expression inheritance level pattern string |
| | | * parsed from the bind rule string. |
| | | */ |
| | | public static |
| | | final int MSGID_ACI_SYNTAX_INVALID_INHERITANCE_VALUE = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 32; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a target rule had an invalid syntax. |
| | | * This takes one argument, which is the target rule string |
| | | * parsed from the "aci" attribute type value string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_TARGET_SYNTAX = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 33; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of an invalid target keyword. This |
| | | * takes one argument, which is the target keyword string parsed |
| | | * from the "aci" attribute type value string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_TARGET_KEYWORD = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 34; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of an invalid target keyword operator. |
| | | * This takes one argument, which is the target keyword operator string |
| | | * parsed from the "aci" attribute type value string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_TARGET_OPERATOR = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 35; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of a target keyword is not supported |
| | | * at this time. This takes one argument, which is the unsupported target |
| | | * keyword string parsed from the "aci" attribute type value string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_TARGET_KEYWORD_NOT_SUPPORTED = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 36; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of a target keyword was seen multiple |
| | | * times in the value. This takes two arguments, which are the target |
| | | * keyword string parsed from the "aci" attribute type value string and |
| | | * the "aci" attribute type value string. |
| | | */ |
| | | public static |
| | | final int MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 37; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of an invalid targetscope keyword |
| | | * operator. This takes one argument, which is the targetscope keyword |
| | | * operator string parsed from the "aci" attribute type value string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_TARGETSCOPE_OPERATOR = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 38; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of an invalid targetscope expression. |
| | | * This takes one argument, which is the targetscope expression |
| | | * string parsed from the "aci" attribute type value string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_TARGETSCOPE_EXPRESSION = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 39; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of an invalid target keyword |
| | | * expression. This takes one argument, which is the target keyword |
| | | * expression string parsed from the "aci" attribute type value string. |
| | | */ |
| | | public static final int MSGID_ACI_SYNTAX_INVALID_TARGETKEYWORD_EXPRESSION = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 40; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of a target keyword DN is not a |
| | | * descendant of the ACI entry DN. This takes two arguments, which are |
| | | * the target keyword DN string parsed from the "aci" attribute type value |
| | | * string and the DN of the "aci" attribute type entry. |
| | | */ |
| | | public static |
| | | final int MSGID_ACI_SYNTAX_TARGET_DN_NOT_DESCENDENTOF = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 41; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of a targetattr keyword expression |
| | | * is invalid. This takes one argument, which is the targetattr |
| | | * keyword expression string parsed from the "aci" attribute type value |
| | | * string. |
| | | */ |
| | | public static |
| | | final int MSGID_ACI_SYNTAX_INVALID_TARGETATTRKEYWORD_EXPRESSION = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 42; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value failed parsing because of a targetfilter keyword expression |
| | | * string is invalid. This takes one argument, which is the targetfilter |
| | | * keyword expression string parsed from the "aci" attribute type value |
| | | * string. |
| | | */ |
| | | public static |
| | | final int MSGID_ACI_SYNTAX_INVALID_TARGETFILTERKEYWORD_EXPRESSION = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 43; |
| | | |
| | | /** |
| | | * The message ID for the ACI message that will be generated when a client |
| | | * attempts to add an entry with the "aci" attribute type |
| | | * and they do not have the required "modify-acl"privilege. This takes two |
| | | * arguments, which are the string representation of the entry DN of the |
| | | * entry being added, and the string representation of the |
| | | * authorization DN. |
| | | */ |
| | | public static final int MSGID_ACI_ADD_FAILED_PRIVILEGE = |
| | | CATEGORY_MASK_ACCESS_CONTROL | 44; |
| | | |
| | | |
| | | /** |
| | | * The message ID for the ACI message that will be generated when a client |
| | | * attempts to perform a modification on an "aci" attribute type |
| | | * and they do not have the required "modify-acl"privilege. This takes two |
| | | * arguments, which are the string representation of the entry DN of the |
| | | * entry being modified, and the string representation of the |
| | | * authorization DN. |
| | | */ |
| | | public static final int MSGID_ACI_MODIFY_FAILED_PRIVILEGE = |
| | | CATEGORY_MASK_ACCESS_CONTROL | 45; |
| | | |
| | | /** |
| | | * The message ID for the ACI message that will be generated when a client |
| | | * attempts to add an entry with the "aci" attribute type |
| | | * and the ACI decode failed because of an syntax error. This takes one |
| | | * argument, which is the message string thrown by the AciException. |
| | | */ |
| | | public static final int MSGID_ACI_ADD_FAILED_DECODE = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 46; |
| | | |
| | | /** |
| | | * The message ID for the ACI message that will be generated when a client |
| | | * attempts to perform a modification on an "aci" attribute type |
| | | * and the ACI decode failed because of a syntax error. This takes one |
| | | * argument, which is the message string thrown by the AciException. |
| | | */ |
| | | public static final int MSGID_ACI_MODIFY_FAILED_DECODE = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 47; |
| | | |
| | | /** |
| | | * The message ID for the ACI message that will be generated when |
| | | * an ACI decode failed because of an syntax error. This message is usually |
| | | * generated by an invalid ACI that was added during import which |
| | | * fails the decode at server startup. This takes one |
| | | * argument, which is the message string thrown by the AciException. |
| | | */ |
| | | public static final int MSGID_ACI_ADD_LIST_FAILED_DECODE = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 48; |
| | | |
| | | /** |
| | | * The message ID for the ACI message that will be generated the server |
| | | * searches an directory context for "aci" attribute types and finds none. |
| | | * This takes one argument, which is the DN of the directory context. |
| | | */ |
| | | public static final int MSGID_ACI_ADD_LIST_NO_ACIS = |
| | | CATEGORY_MASK_ACCESS_CONTROL | 49; |
| | | |
| | | /** |
| | | * The message ID for the ACI message that will be generated the server |
| | | * searches an directory context for "aci" attribute types and finds some. |
| | | * This takes two arguments, which are the DN of the directory context, |
| | | * the number of valid ACIs decoded. |
| | | */ |
| | | public static final int MSGID_ACI_ADD_LIST_ACIS = |
| | | CATEGORY_MASK_ACCESS_CONTROL | 50; |
| | | |
| | | /** |
| | | * The message ID for the message that will be used if an "aci" attribute |
| | | * type value parse failed because a bind rule userattr roledn expression |
| | | * inheritance pattern did not parse. This takes one argument, which |
| | | * is the userattr expression inheritance pattern string parsed |
| | | * from the bind rule string. |
| | | */ |
| | | public static |
| | | final int MSGID_ACI_SYNTAX_INVALID_USERATTR_ROLEDN_INHERITANCE_PATTERN = |
| | | CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 51; |
| | | /** |
| | | * Associates a set of generic messages with the message IDs defined in |
| | | * this class. |
| | | */ |
| | | public static void registerMessages() { |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_GENERAL_PARSE_FAILED, |
| | | "The provided string \"%s\" could not be parsed as a valid " + |
| | | "Access Control Instruction (ACI) because it failed "+ |
| | | "general ACI syntax evaluation."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVAILD_VERSION, |
| | | "The provided Access Control Instruction (ACI) version " + |
| | | "value \"%s\" is invalid, only the version 3.0 is " + |
| | | "supported."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_ACCESS_TYPE_VERSION, |
| | | "The provided Access Control Instruction access " + |
| | | "type value \"%s\" is invalid. A valid access type " + |
| | | "value is either allow or deny."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_RIGHTS_SYNTAX, |
| | | "The provided Access Control Instruction (ACI) rights " + |
| | | "values \"%s\" are invalid. The rights must be a " + |
| | | "list of 1 to 6 comma-separated keywords enclosed in " + |
| | | "parentheses."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_RIGHTS_KEYWORD, |
| | | "The provided Access Control Instruction (ACI) rights " + |
| | | "keyword values \"%s\" are invalid. The valid rights " + |
| | | "keyword values are one or more of the following: read, " + |
| | | "write, add, delete, search, compare or the single value" + |
| | | "all."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_BIND_RULE_MISSING_CLOSE_PAREN, |
| | | "The provided Access Control Instruction (ACI) bind " + |
| | | "rule value \"%s\" is invalid because it is missing a " + |
| | | "close parenthesis that corresponded to the initial open " + |
| | | "parenthesis."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_BIND_RULE_SYNTAX, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "value \"%s\" is invalid. A valid bind rule value must " + |
| | | "be in the following form: " + |
| | | "keyword operator \"expression\"."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "keyword value \"%s\" is invalid. A valid keyword value is" + |
| | | " one of the following: userdn, groupdn, roledn, userattr," + |
| | | "ip, dns, dayofweek, timeofday or authmethod."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_BIND_RULE_OPERATOR , |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "operator value \"%s\" is invalid. A valid bind rule " + |
| | | "operator value is either '=' or \"!=\"."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_MISSING_BIND_RULE_EXPRESSION , |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "expression value corresponding to the keyword value " + |
| | | "\"%s\" is missing an expression. A valid bind rule value " + |
| | | "must be in the following form:" + |
| | | " keyword operator \"expression\"."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_BIND_RULE_BOOLEAN_OPERATOR , |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "boolean operator value \"%s\" is invalid. A valid bind" + |
| | | "rule boolean operator value is either \"OR\" or \"AND\"."); |
| | | |
| | | registerMessage( |
| | | MSGID_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD_OPERATOR_COMBO, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "keyword string \"%s\" is invalid for the bind rule " + |
| | | "operator string \"%s\"."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_USERDN_URL, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "userdn expression failed to URL decode for " + |
| | | "the following reason: %s"); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_ROLEDN_EXPRESSION, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "roledn expression value \"%s\" is invalid. A valid roledn " + |
| | | "keyword expression value requires one or more LDAP URLs " + |
| | | "in the following format: " + |
| | | "ldap:///dn [|| ldap:///dn] ... [|| ldap:///dn]."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_ROLEDN_URL, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "roledn expression failed to URL decode for " + |
| | | "the following reason: %s"); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_GROUPDN_EXPRESSION, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "groupdn expression value \"%s\" is invalid. A valid groupdn " + |
| | | "keyword expression value requires one or more LDAP URLs in the" + |
| | | " following format: " + |
| | | "ldap:///groupdn [|| ldap:///groupdn] ... [|| ldap:///groupdn]."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_GROUPDN_URL, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "groupdn expression value failed to URL decode for " + |
| | | "the following reason: %s"); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_ADDRESS_FAMILY_MISMATCH, |
| | | "The network mask value \"%s\" is not valid for " + |
| | | "the ip expression network address \"%s\"."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_NETWORK_BIT_MATCH, |
| | | "The bit mask for address type value \"%s\" is not valid." + |
| | | "%s."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_IP_CRITERIA_DECODE, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "ip expression value failed to decode for " + |
| | | "the following reason: %s"); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_IP_EXPRESSION, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "ip expression value \"%s\" is invalid. A valid ip " + |
| | | "keyword expression value requires one or more" + |
| | | "comma-separated elements of an IP address list expression."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_DNS_EXPRESSION, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "dns expression value \"%s\" is invalid. A valid dns " + |
| | | "keyword expression value requires a valid fully qualified"+ |
| | | " DNS domain name."); |
| | | |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_DNS_WILDCARD, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "dns expression value \"%s\" is invalid, because a wild-card" + |
| | | " pattern was found in the wrong position. A valid dns " + |
| | | "keyword wild-card expression value requires the '*' " + |
| | | "character only be in the leftmost position of the " + |
| | | "domain name."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_DAYOFWEEK, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "dayofweek expression value \"%s\" is invalid, because of " + |
| | | "an invalid day of week value. A valid dayofweek value " + |
| | | "is one of the following English three-letter abbreviations" + |
| | | "for the days of the week: sun, mon, tue, wed, thu, " + |
| | | "fri, or sat."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_TIMEOFDAY, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "timeofday expression value \"%s\" is invalid. A valid " + |
| | | "timeofday value is expressed as four digits representing " + |
| | | "hours and minutes in the 24-hour clock (0 to 2359)."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_TIMEOFDAY_RANGE, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "timeofday expression value \"%s\" is not in the valid" + |
| | | " range. A valid timeofday value is expressed as four" + |
| | | " digits representing hours and minutes in the 24-hour" + |
| | | " clock (0 to 2359)."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_AUTHMETHOD_EXPRESSION, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "authmethod expression value \"%s\" is invalid. A valid " + |
| | | "authmethod value is one of the following: none, simple," + |
| | | "SSL, sasl EXTERNAL, sasl DIGEST-MD5, or sasl GSSAPI."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_USERATTR_EXPRESSION, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "userattr expression value \"%s\" is invalid."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_USERATTR_KEYWORD, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "userattr expression value \"%s\" is not supported."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_USERATTR_INHERITANCE_PATTERN, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "userattr expression inheritance pattern value \"%s\" is " + |
| | | "invalid. A valid inheritance pattern value must have" + |
| | | "the following format:" + |
| | | " parent[inheritance_level].attribute#bindType."); |
| | | |
| | | registerMessage( |
| | | MSGID_ACI_SYNTAX_MAX_USERATTR_INHERITANCE_LEVEL_EXCEEDED, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "userattr expression inheritance pattern value \"%s\" is " + |
| | | "invalid. The inheritance level value cannot exceed the" + |
| | | "max level limit of %s."); |
| | | |
| | | registerMessage( |
| | | MSGID_ACI_SYNTAX_INVALID_INHERITANCE_VALUE, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "userattr expression inheritance pattern value \"%s\" is" + |
| | | " invalid because it is non-numeric."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGET_SYNTAX, |
| | | "The provided Access Control Instruction (ACI) target rule" + |
| | | "value \"%s\" is invalid. A valid target rule value must" + |
| | | "be in the following form: " + |
| | | "keyword operator \"expression\"."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGET_KEYWORD, |
| | | "The provided Access Control Instruction (ACI) target " + |
| | | "keyword value \"%s\" is invalid. A valid target keyword" + |
| | | " value is one of the following: target, targetscope, " + |
| | | "targetfilter, targetattr or targetattrfilters."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGET_OPERATOR, |
| | | "The provided Access Control Instruction (ACI) target " + |
| | | "keyword operator value \"%s\" is invalid. A valid target" + |
| | | "keyword operator value is either '=' or \"!=\"."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_TARGET_KEYWORD_NOT_SUPPORTED, |
| | | "The provided Access Control Instruction (ACI) " + |
| | | "target keyword value \"%s\" is not supported at this time."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS, |
| | | "The provided Access Control Instruction (ACI) " + |
| | | "target keyword value \"%s\" was seen multiple times in" + |
| | | " the ACI \"%s\"."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGETSCOPE_OPERATOR, |
| | | "The provided Access Control Instruction (ACI) targetscope" + |
| | | " keyword operator value \"%s\" is invalid. The only valid" + |
| | | "targetscope operator value is '='."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGETSCOPE_EXPRESSION, |
| | | "The provided Access Control Instruction (ACI) targetscope" + |
| | | " expression operator value \"%s\" is invalid. A valid" + |
| | | " targetscope expression value is one of the following: one," + |
| | | " onelevel or subtree."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGETKEYWORD_EXPRESSION, |
| | | "The provided Access Control Instruction (ACI)" + |
| | | " target expression value \"%s\" is invalid. A valid target" + |
| | | " keyword expression value requires a LDAP URL in the" + |
| | | " following format: ldap:///distinguished_name."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_TARGET_DN_NOT_DESCENDENTOF, |
| | | "The provided Access Control Instruction (ACI) " + |
| | | "target expression DN value \"%s\" is invalid. The target " + |
| | | "expression DN value must be a descendant of the ACI entry" + |
| | | " DN \"%s\", if no wild-card is specified in the target" + |
| | | "expression DN."); |
| | | |
| | | registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGETATTRKEYWORD_EXPRESSION, |
| | | "The provided Access Control Instruction (ACI) " + |
| | | "targetattr expression value \"%s\" is invalid. A valid " + |
| | | "targetattr keyword expression value requires one or more " + |
| | | "attribute type values in the following format: " + |
| | | "attribute1 [|| attribute1] ... [|| attributen]."); |
| | | |
| | | registerMessage( |
| | | MSGID_ACI_SYNTAX_INVALID_TARGETFILTERKEYWORD_EXPRESSION, |
| | | "The provided Access Control Instruction (ACI)" + |
| | | " targetfilter expression value \"%s\" is invalid because it" + |
| | | " is not a valid LDAP filter."); |
| | | |
| | | registerMessage(MSGID_ACI_ADD_FAILED_PRIVILEGE, |
| | | "An attempt to add the entry \"%s\" containing" + |
| | | " an aci attribute type failed, because the authorization DN" + |
| | | " \"%s\" lacked modify-acl privileges."); |
| | | |
| | | registerMessage(MSGID_ACI_MODIFY_FAILED_PRIVILEGE, |
| | | "An attempt to modify an aci "+ |
| | | "attribute type in the entry \"%s\" failed, because the" + |
| | | "authorization DN \"%s\" lacked modify-acl privileges."); |
| | | |
| | | registerMessage(MSGID_ACI_ADD_FAILED_DECODE, |
| | | "An attempt to add the entry \"%s\" containing" + |
| | | " an aci attribute type failed because of the following" + |
| | | " reason: %s"); |
| | | |
| | | registerMessage(MSGID_ACI_MODIFY_FAILED_DECODE, |
| | | "An attempt to modify an aci "+ |
| | | "attribute type in the entry \"%s\" failed "+ |
| | | "because of the following reason: %s"); |
| | | |
| | | registerMessage(MSGID_ACI_ADD_LIST_FAILED_DECODE, |
| | | "An attempt to decode an Access Control Instruction (ACI)" + |
| | | " failed because of the following reason: %s"); |
| | | |
| | | registerMessage(MSGID_ACI_ADD_LIST_NO_ACIS, |
| | | "No Access Control Instruction (ACI) attribute types were" + |
| | | " found in context \"%s\"."); |
| | | |
| | | registerMessage(MSGID_ACI_ADD_LIST_ACIS, |
| | | "Added %s Access Control Instruction (ACI) attribute types" + |
| | | " found in context \"%s\" to the access" + |
| | | "control evaluation engine."); |
| | | |
| | | registerMessage( |
| | | MSGID_ACI_SYNTAX_INVALID_USERATTR_ROLEDN_INHERITANCE_PATTERN, |
| | | "The provided Access Control Instruction (ACI) bind rule " + |
| | | "userattr expression inheritance pattern value " + |
| | | "\"%s\" is invalid for the roledn keyword because it starts " + |
| | | "with the string \"parent[\"."); |
| | | } |
| | | } |
| 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.api.AccessControlHandler; |
| | | import org.opends.server.api.AccessControlProvider; |
| | | import org.opends.server.config.ConfigEntry; |
| | | import org.opends.server.config.ConfigException; |
| | | import org.opends.server.types.InitializationException; |
| | | import static org.opends.server.loggers.Debug.debugConstructor; |
| | | |
| | | /** |
| | | * This class is the provider class for the dseecompt ACI. |
| | | */ |
| | | public class AciProvider implements AccessControlProvider { |
| | | |
| | | private static final String CLASS_NAME = |
| | | "org.opends.server.authorization.dseecompat.AciProvider"; |
| | | |
| | | private static AciHandler instance = null; |
| | | |
| | | /** |
| | | * Create an aci provider. This doesn't do much. |
| | | */ |
| | | public AciProvider() { |
| | | super(); |
| | | assert debugConstructor(CLASS_NAME); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Creates the AciHandler class and calls its initialization method. |
| | | * @param configEntry The entry containing the configuration Access Control |
| | | * entry. |
| | | * @throws ConfigException If the initialization fails. |
| | | * @throws InitializationException If the initialization fails. |
| | | */ |
| | | public void initializeAccessControlHandler(ConfigEntry configEntry) |
| | | throws ConfigException, InitializationException { |
| | | getInstance(); |
| | | } |
| | | |
| | | /** |
| | | * Returns a new AciHandler instance. There can be only one active. |
| | | * @return A new AciHandler instance. |
| | | */ |
| | | public AccessControlHandler getInstance() { |
| | | if (instance == null) { |
| | | instance = new AciHandler(); |
| | | } |
| | | return instance; |
| | | } |
| | | |
| | | /** |
| | | * Not used at this time. |
| | | */ |
| | | public void finalizeAccessControlHandler() { |
| | | |
| | | } |
| | | } |
| 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.AttributeType; |
| | | import org.opends.server.types.AttributeValue; |
| | | import org.opends.server.types.Entry; |
| | | import java.util.LinkedList; |
| | | |
| | | /** |
| | | * The AciTargetMatchContext interface provides a |
| | | * view of an AciContainer that exposes information to be |
| | | * used by the Aci.isApplicable() method to determine if |
| | | * an ACI is applicable (targets matched) to the LDAP operation, |
| | | * operation rights and entry and attributes having access |
| | | * checked on. |
| | | */ |
| | | public interface AciTargetMatchContext { |
| | | /** |
| | | * Set the deny ACI list. |
| | | * @param denyList The deny ACI list. |
| | | */ |
| | | public void setDenyList(LinkedList<Aci> denyList); |
| | | |
| | | /** |
| | | * Set the allow ACI list. |
| | | * @param allowList The list of allow ACIs. |
| | | */ |
| | | public void setAllowList(LinkedList<Aci> allowList); |
| | | |
| | | /** |
| | | * Get the entry being evaluated. This is known as the |
| | | * resource entry. |
| | | * @return The entry being evaluated. |
| | | */ |
| | | public Entry getResourceEntry(); |
| | | |
| | | /** |
| | | * Get the current attribute type being evaluated. |
| | | * @return The attribute type being evaluated. |
| | | */ |
| | | public AttributeType getCurrentAttributeType(); |
| | | |
| | | /** |
| | | * The current attribute type value being evaluated. |
| | | * @return The current attribute type value being evaluated. |
| | | */ |
| | | public AttributeValue getCurrentAttributeValue(); |
| | | |
| | | /** |
| | | * True if the first attribute of the resource entry is being evaluated. |
| | | * @return True if this is the first attribute. |
| | | */ |
| | | public boolean isFirstAttribute(); |
| | | |
| | | /** |
| | | * Set to true if the first attribute of the resource entry is |
| | | * being evaluated. |
| | | * @param isFirst True if this is the first attribute of the |
| | | * resource entry being evaluated. |
| | | */ |
| | | public void setIsFirstAttribute(boolean isFirst); |
| | | |
| | | /** |
| | | * Set the attribute type to be evaluated. |
| | | * @param type The attribute type to set to. |
| | | */ |
| | | public void setCurrentAttributeType(AttributeType type); |
| | | |
| | | /** |
| | | * Set the attribute value to be evaluated. |
| | | * @param v The current attribute value to set to. |
| | | */ |
| | | public void setCurrentAttributeValue(AttributeValue v); |
| | | |
| | | /** |
| | | * True if the target matching code found an entry test rule. An |
| | | * entry test rule is an ACI without a targetattr target rule. |
| | | * @param val True if an entry test rule was found. |
| | | */ |
| | | public void setEntryTestRule(boolean val); |
| | | |
| | | /** |
| | | * True if an entry test rule was found. |
| | | * @return True if an entry test rule was found. |
| | | */ |
| | | public boolean hasEntryTestRule(); |
| | | |
| | | /** |
| | | * Return the rights for this container's LDAP operation. |
| | | * @return The rights for the container's LDAP operation. |
| | | */ |
| | | public int getRights(); |
| | | |
| | | /** |
| | | * 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. |
| | | */ |
| | | public boolean hasRights(int rights); |
| | | |
| | | /** |
| | | * Set the rights of the container to the specified rights. |
| | | * @param rights The rights to set the container's rights to. |
| | | */ |
| | | public void setRights(int rights); |
| | | } |
| | | |
| | | |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.SearchScope; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | | /** |
| | | * This class represents target part of an ACI's syntax. This is the part |
| | | * of an ACI before the ACI body and specifies the entry, attributes, or set |
| | | * of entries and attributes which the ACI controls access. |
| | | * |
| | | * The four supported ACI target keywords currently |
| | | * supported are: target, targetattr, targetscope and targetfilter. |
| | | * Missing is support for targetattrfilters. |
| | | */ |
| | | public class AciTargets { |
| | | /* |
| | | * ACI syntax has a target keyword. |
| | | */ |
| | | private Target target = null ; |
| | | /* |
| | | * ACI syntax has a targetscope keyword. |
| | | */ |
| | | private SearchScope targetScope = SearchScope.WHOLE_SUBTREE; |
| | | /* |
| | | * ACI syntax has a targetattr keyword. |
| | | */ |
| | | private TargetAttr targetAttr = null ; |
| | | /* |
| | | * ACI syntax has a targetfilter keyword. |
| | | */ |
| | | private TargetFilter targetFilter=null; |
| | | |
| | | private TargAttrFilters targAttrFilters=null; |
| | | /* |
| | | * These are used in the regular expression parsing. |
| | | */ |
| | | private static final int targetElementCount = 3; |
| | | private static final int targetKeywordPos = 1; |
| | | private static final int targetOperatorPos = 2; |
| | | private static final int targetExpressionPos = 3; |
| | | /* |
| | | * TODO Make the regular expression strings below easier to |
| | | * understand. |
| | | * |
| | | * The same note earlier about making regex values easier to |
| | | * understand applies to this class as well. |
| | | */ |
| | | private static final String targetRegex = |
| | | "\\(\\s*(\\w+)\\s*(!?=)\\s*\"([^\"]+)\"\\s*\\)\\s*"; |
| | | /** |
| | | * Regular expression used in target matching. |
| | | */ |
| | | public static final String targetsRegex = "(" + targetRegex + ")*"; |
| | | |
| | | /* |
| | | * Rights that are skipped for certain target evaluations. |
| | | * The test is use the skipRights array is: |
| | | * |
| | | * Either the ACI has a targetattr's rule and the current |
| | | * attribute type is null or the current attribute type has |
| | | * a type specified and the targetattr's rule is null. |
| | | * |
| | | * The actual check against the skipRights array is: |
| | | * |
| | | * 1. Is the ACI's rights in this array? For example, |
| | | * allow(all) or deny(add) |
| | | * |
| | | * AND |
| | | * |
| | | * 2. Is the rights from the LDAP operation in this array? For |
| | | * example, an LDAP add would have rights of add and all. |
| | | * |
| | | * If both are true, than the target match test returns true |
| | | * for this ACI. |
| | | */ |
| | | |
| | | private static final int skipRights = |
| | | (AciHandler.ACI_ADD | AciHandler.ACI_DELETE | AciHandler.ACI_PROXY); |
| | | |
| | | /** |
| | | * Creates an ACI target from the specified arguments. All of these |
| | | * may be null -- the ACI has no targets an will use defaults. |
| | | * @param targetEntry The ACI target keyword if any. |
| | | * @param targetAttr The ACI targetattr keyword if any. |
| | | * @param targetFilter The ACI targetfilter keyword if any. |
| | | * @param targetScope The ACI targetscope keyword if any. |
| | | */ |
| | | private AciTargets(Target targetEntry, TargetAttr targetAttr, |
| | | TargetFilter targetFilter, |
| | | SearchScope targetScope) { |
| | | this.target=targetEntry; |
| | | this.targetAttr=targetAttr; |
| | | this.targetScope=targetScope; |
| | | this.targetFilter=targetFilter; |
| | | } |
| | | |
| | | /** |
| | | * Return class representing the ACI target keyword. May be |
| | | * null. The default is the use the DN of the entry containing |
| | | * the ACI and check if the resource entry is a descendant of that. |
| | | * @return The ACI target class. |
| | | */ |
| | | public Target getTarget() { |
| | | return target; |
| | | } |
| | | |
| | | /** |
| | | * Return class representing the ACI targetattr keyword. May be null. |
| | | * The default is to not match any attribute types in an entry. |
| | | * @return The ACI targetattr class. |
| | | */ |
| | | public TargetAttr getTargetAttr() { |
| | | return targetAttr; |
| | | } |
| | | |
| | | /** |
| | | * Return the ACI targetscope keyword. Default is WHOLE_SUBTREE. |
| | | * @return The ACI targetscope information. |
| | | */ |
| | | public SearchScope getTargetScope() { |
| | | return targetScope; |
| | | } |
| | | |
| | | /** |
| | | * Return class representing the ACI targetfilter keyword. May be null. |
| | | * @return The targetscope information. |
| | | */ |
| | | public TargetFilter getTargetFilter() { |
| | | return targetFilter; |
| | | } |
| | | |
| | | /** |
| | | * Decode an ACI's target part of the syntax from the string provided. |
| | | * @param input String representing an ACI target part of syntax. |
| | | * @param dn The DN of the entry containing the ACI. |
| | | * @return An AciTargets class representing the decoded ACI target string. |
| | | * @throws AciException If the provided string contains errors. |
| | | */ |
| | | public static AciTargets decode(String input, DN dn) |
| | | throws AciException { |
| | | Target target=null; |
| | | TargetAttr targetAttr=null; |
| | | TargetFilter targetFilter=null; |
| | | TargAttrFilters targAttrFilters=null; |
| | | SearchScope targetScope=SearchScope.WHOLE_SUBTREE; |
| | | Pattern targetPattern = Pattern.compile(targetRegex); |
| | | Matcher targetMatcher = targetPattern.matcher(input); |
| | | while (targetMatcher.find()) |
| | | { |
| | | if (targetMatcher.groupCount() != targetElementCount) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_TARGET_SYNTAX; |
| | | String message = getMessage(msgID, input); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | String keyword = targetMatcher.group(targetKeywordPos); |
| | | EnumTargetKeyword targetKeyword = |
| | | EnumTargetKeyword.createKeyword(keyword); |
| | | if (targetKeyword == null) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_TARGET_KEYWORD; |
| | | String message = getMessage(msgID, keyword ); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | String operator = |
| | | targetMatcher.group(targetOperatorPos); |
| | | EnumTargetOperator targetOperator = |
| | | EnumTargetOperator.createOperator(operator); |
| | | if (targetOperator == null) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_TARGET_OPERATOR; |
| | | String message = getMessage(msgID, operator); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | String expression = targetMatcher.group(targetExpressionPos); |
| | | switch(targetKeyword) |
| | | { |
| | | case KEYWORD_TARGET: |
| | | { |
| | | if (target == null){ |
| | | target = Target.decode(targetOperator, expression, dn); |
| | | } |
| | | else |
| | | { |
| | | int msgID = |
| | | MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS; |
| | | String message = |
| | | getMessage(msgID, "target", input); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | break; |
| | | } |
| | | case KEYWORD_TARGETATTR: |
| | | { |
| | | if (targetAttr == null){ |
| | | targetAttr = TargetAttr.decode(targetOperator, |
| | | expression); |
| | | } |
| | | else { |
| | | int msgID = |
| | | MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS; |
| | | String message = |
| | | getMessage(msgID, "targetattr", input); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | break; |
| | | } |
| | | case KEYWORD_TARGETSCOPE: |
| | | { |
| | | // Check the operator for the targetscope is EQUALITY |
| | | if (targetOperator == EnumTargetOperator.NOT_EQUALITY) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_TARGETSCOPE_OPERATOR; |
| | | String message = getMessage(msgID, operator); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | targetScope=createScope(expression); |
| | | break; |
| | | } |
| | | case KEYWORD_TARGETFILTER: |
| | | { |
| | | if (targetFilter == null){ |
| | | targetFilter = TargetFilter.decode(targetOperator, |
| | | expression); |
| | | } |
| | | else { |
| | | int msgID = |
| | | MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS; |
| | | String message = |
| | | getMessage(msgID, "targetfilter", input); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | break; |
| | | } |
| | | case KEYWORD_TARGATTRFILTERS: |
| | | { |
| | | if (targAttrFilters == null){ |
| | | targAttrFilters = TargAttrFilters.decode(targetOperator, |
| | | expression); |
| | | } |
| | | else { |
| | | int msgID = |
| | | MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS; |
| | | String message = |
| | | getMessage(msgID, "targattrfilters", input); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | return new AciTargets(target, targetAttr, targetFilter, targetScope); |
| | | } |
| | | |
| | | /* |
| | | * TODO Add support for the SearchScope.SUBORDINATE_SUBTREE scope. |
| | | */ |
| | | /** |
| | | * Evaluates a provided scope string and returns an appropriate |
| | | * SearchScope enumeration. |
| | | * @param expression The expression string. |
| | | * @return An search scope enumeration matching the string. |
| | | * @throws AciException If the expression is an invalid targetscope |
| | | * string. |
| | | */ |
| | | private static SearchScope createScope(String expression) |
| | | throws AciException { |
| | | if(expression.equalsIgnoreCase("base")) |
| | | return SearchScope.BASE_OBJECT; |
| | | else if(expression.equalsIgnoreCase("onelevel")) |
| | | return SearchScope.SINGLE_LEVEL; |
| | | else if(expression.equalsIgnoreCase("subtree")) |
| | | return SearchScope.WHOLE_SUBTREE; |
| | | else { |
| | | int msgID = |
| | | MSGID_ACI_SYNTAX_INVALID_TARGETSCOPE_EXPRESSION; |
| | | String message = getMessage(msgID, expression); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Checks an ACI's targetfilter information against an target match |
| | | * context. |
| | | * @param aci The ACI to try an match the targetfilter of. |
| | | * @param matchCtx The target match context containing information needed |
| | | * to perform a target match. |
| | | * @return True if the targetfilter matched the target context. |
| | | */ |
| | | public static boolean isTargetFilterApplicable(Aci aci, |
| | | AciTargetMatchContext matchCtx) { |
| | | boolean ret=true; |
| | | TargetFilter targetFilter=aci.getTargets().getTargetFilter(); |
| | | if(targetFilter != null) |
| | | ret=targetFilter.isApplicable(matchCtx); |
| | | return ret; |
| | | } |
| | | |
| | | /* |
| | | * TODO Evaluate making this method more efficient. |
| | | * The isTargetAttrApplicable method looks a lot less efficient than it |
| | | * could be with regard to the logic that it employs and the repeated use |
| | | * of method calls over local variables. |
| | | */ |
| | | /** |
| | | * Checks an provided ACI's targetattr information against a target match |
| | | * context. |
| | | * @param aci The ACI to evaluate. |
| | | * @param targetMatchCtx The target match context to check the ACI against. |
| | | * @return True if the targetattr matched the target context. |
| | | */ |
| | | public static boolean isTargetAttrApplicable(Aci aci, |
| | | AciTargetMatchContext targetMatchCtx) { |
| | | boolean ret=true; |
| | | AciTargets targets=aci.getTargets(); |
| | | AttributeType a=targetMatchCtx.getCurrentAttributeType(); |
| | | int rights=targetMatchCtx.getRights(); |
| | | boolean isFirstAttr=targetMatchCtx.isFirstAttribute(); |
| | | if((a != null) && (targets.getTargetAttr() != null)) { |
| | | ret=TargetAttr.isApplicable(a, targets.getTargetAttr()); |
| | | } else if((a != null) || (targets.getTargetAttr() != null)) { |
| | | if((aci.hasRights(skipRights)) && (skipRightsHasRights(rights))) { |
| | | ret=true; |
| | | } else if ((targets.getTargetAttr() != null) && |
| | | (a == null) && (aci.hasRights(AciHandler.ACI_WRITE))) { |
| | | ret = true; |
| | | } else { |
| | | ret = false; |
| | | } |
| | | } |
| | | if((isFirstAttr) && (aci.getTargets().getTargetAttr() == null)) |
| | | targetMatchCtx.setEntryTestRule(true); |
| | | return ret; |
| | | } |
| | | |
| | | /** |
| | | * Try and match a one or more of the specified rights in the skiprights |
| | | * mask. |
| | | * @param rights The rights to check for. |
| | | * @return True if the one or more of the specified rights are in the |
| | | * skiprights rights mask. |
| | | */ |
| | | public static boolean skipRightsHasRights(int rights) { |
| | | return ((skipRights & rights) == rights); |
| | | } |
| | | |
| | | /* |
| | | * TODO Track DS 6.1 changes to ONELEVEL scope. |
| | | * |
| | | * The isTargetApplicable method appears to handle the ONELEVEL scope |
| | | * incorrectly. The standard definition of onelevel only includes |
| | | * the immediate children of a given entry -- it does not include that |
| | | * entry itself. It is a bug for the server to behave in any other way. |
| | | * Unfortunately, it does appear that the implementation you currently |
| | | * have matches the implementation in DS6. Nevertheless, I don't think |
| | | * that it is acceptable use this standard term in a nonstandard way and |
| | | * therefore we must change it to the standards-compliant interpretation |
| | | * which does not include the parent. |
| | | * |
| | | * TODO Investigate supporting alternative representations of the scope. |
| | | * |
| | | * Should we also consider supporting alternate representations of the |
| | | * scope values (in particular, allow "one" in addition to "onelevel" |
| | | * and "sub" in addition to "subtree") to match the very common |
| | | * abbreviations in widespread use for those terms? |
| | | */ |
| | | /** |
| | | * Checks an provided ACI's target information against an target match |
| | | * context. |
| | | * @param aci The ACI to match the target against. |
| | | * @param matchCtx The target match context to check the ACI against. |
| | | * @return True if the target matched the context. |
| | | */ |
| | | public static boolean isTargetApplicable(Aci aci, |
| | | AciTargetMatchContext matchCtx) { |
| | | boolean ret=true; |
| | | DN entryDN=matchCtx.getResourceEntry().getDN(); |
| | | DN targetDN=aci.getDN(); |
| | | AciTargets targets=aci.getTargets(); |
| | | |
| | | /* |
| | | * Scoping of the ACI uses either the DN of the entry |
| | | * containing the ACI (aci.getDN above), or if the ACI item |
| | | * contains a simple target DN and a equality operator that |
| | | * target DN is used. |
| | | */ |
| | | if((targets.getTarget() != null) && |
| | | (!targets.getTarget().isPattern())) { |
| | | EnumTargetOperator op=targets.getTarget().getOperator(); |
| | | if(op != EnumTargetOperator.NOT_EQUALITY) |
| | | targetDN=targets.getTarget().getDN(); |
| | | } |
| | | switch(targets.getTargetScope()) { |
| | | case BASE_OBJECT: |
| | | if(!targetDN.equals(entryDN)) |
| | | return false; |
| | | break; |
| | | case SINGLE_LEVEL: |
| | | if((!targetDN.equals(entryDN)) && |
| | | (!entryDN.getParent().equals(targetDN))) |
| | | return false; |
| | | break; |
| | | case WHOLE_SUBTREE: |
| | | if(!entryDN.isDescendantOf(targetDN)) |
| | | return false; |
| | | break; |
| | | /* |
| | | * TODO Add support for the SearchScope.SUBORDINATE_SUBTREE scope. |
| | | * |
| | | * The isTargetApplicable method doesn't account for the subordinate |
| | | * subtree search scope. |
| | | */ |
| | | default: |
| | | return false; |
| | | } |
| | | /* |
| | | * The entry is in scope. For inequality checks, scope was tested |
| | | * against the entry containing the ACI. If operator is inequality, |
| | | * check that it doesn't match the target DN. |
| | | */ |
| | | if((targets.getTarget() != null) && |
| | | (!targets.getTarget().isPattern())) { |
| | | EnumTargetOperator op=targets.getTarget().getOperator(); |
| | | if(op == EnumTargetOperator.NOT_EQUALITY) { |
| | | DN tmpDN=targets.getTarget().getDN(); |
| | | if(entryDN.isDescendantOf(tmpDN)) |
| | | return false; |
| | | } |
| | | } |
| | | /* |
| | | * There is a pattern, need to match the substring filter |
| | | * created when the ACI was decoded. If inequality flip the |
| | | * result. |
| | | */ |
| | | if((targets.getTarget() != null) && |
| | | (targets.getTarget().isPattern())) { |
| | | ret=targets.getTarget().matchesPattern(entryDN); |
| | | EnumTargetOperator op=targets.getTarget().getOperator(); |
| | | if(ret && op == 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.authorization.dseecompat; |
| | | |
| | | import static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | |
| | | /** |
| | | * The AuthMethod class represents an authmethod bind rule keyword expression. |
| | | */ |
| | | public class AuthMethod implements KeywordBindRule { |
| | | private EnumAuthMethod authMethod=null; |
| | | private EnumBindRuleType type=null; |
| | | |
| | | /** |
| | | * Create a class representing an authmethod bind rule keyword from the |
| | | * provided method and bind rule type. |
| | | * @param method An enumeration representing the method of the expression. |
| | | * @param type An enumeration representing the type of the expression. |
| | | */ |
| | | private AuthMethod(EnumAuthMethod method, EnumBindRuleType type) { |
| | | this.authMethod=method; |
| | | this.type=type; |
| | | } |
| | | |
| | | /** |
| | | * Decode a string representing a authmethod bind rule. |
| | | * @param expr The string representing the bind rule. |
| | | * @param type An enumeration representing the bind rule type. |
| | | * @return An keyword bind rule class that can be used to evaluate the |
| | | * bind rule. |
| | | * @throws AciException If the expression string is invalid. |
| | | */ |
| | | public static KeywordBindRule decode(String expr, EnumBindRuleType type) |
| | | throws AciException { |
| | | EnumAuthMethod method=EnumAuthMethod.createAuthmethod(expr); |
| | | if (method == null) |
| | | { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_AUTHMETHOD_EXPRESSION; |
| | | String message = getMessage(msgID, expr); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | return new AuthMethod(method, type); |
| | | } |
| | | |
| | | /* |
| | | * TODO Evaluate if AUTHMETHOD_NONE processing is correct. This was fixed |
| | | * prior to Neil's review. Verify in a unit test. |
| | | * |
| | | * I'm not sure that the evaluate() method handles AUTHMETHOD_NONE |
| | | * correctly. My understanding is that it should only match in cases |
| | | * in which no authentication has been performed, but you have it |
| | | * always matching. |
| | | */ |
| | | /** |
| | | * Evaluate authmethod bind rule using the provided evaluation context. |
| | | * @param evalCtx An evaluation context to use. |
| | | * @return An enumeration evaluation result. |
| | | */ |
| | | public EnumEvalResult evaluate(AciEvalContext evalCtx) { |
| | | EnumEvalResult matched=EnumEvalResult.FALSE; |
| | | if(authMethod==EnumAuthMethod.AUTHMETHOD_NONE) { |
| | | matched=EnumEvalResult.TRUE; |
| | | } else if(authMethod==EnumAuthMethod.AUTHMETHOD_SIMPLE) { |
| | | if(evalCtx.getAuthenticationMethod(false) |
| | | == EnumAuthMethod.AUTHMETHOD_SIMPLE){ |
| | | matched=EnumEvalResult.TRUE; |
| | | } |
| | | } else if(authMethod == EnumAuthMethod.AUTHMETHOD_SSL) { |
| | | /* |
| | | * TODO Verfiy that SSL authemethod is correctly handled in a |
| | | * unit test. |
| | | * I'm not sure that the evaluate() method correctly handles |
| | | * SASL EXTERNAL in all cases. My understanding is that in |
| | | * DS 5/6, an authmethod of SSL is the same as an authmethod of |
| | | * SASL EXTERNAL. If that's true, then you don't properly handle |
| | | * that condition. |
| | | */ |
| | | if(authMethod == evalCtx.getAuthenticationMethod(true)) |
| | | matched=EnumEvalResult.TRUE; |
| | | } else { |
| | | if(authMethod ==evalCtx.getAuthenticationMethod(false)) |
| | | matched=EnumEvalResult.TRUE; |
| | | } |
| | | return matched.getRet(type, false); |
| | | } |
| | | } |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import java.util.regex.Pattern; |
| | | import java.util.regex.Matcher; |
| | | import java.util.HashMap; |
| | | |
| | | /** |
| | | * This class represents a single bind rule of an ACI permission-bind rule |
| | | * pair. |
| | | */ |
| | | public class BindRule { |
| | | /* |
| | | * This hash table holds the keyword bind rule mapping. |
| | | */ |
| | | private HashMap<String, KeywordBindRule> keywordRuleMap = |
| | | new HashMap<String, KeywordBindRule>(); |
| | | |
| | | //True is a boolean "not" was seen. |
| | | private boolean negate=false; |
| | | |
| | | //Complex bind rules have left and right values. |
| | | private BindRule left = null; |
| | | private BindRule right = null; |
| | | |
| | | //Enumeration of the boolean type of the complex bind rule ("and" or "or"). |
| | | private EnumBooleanTypes booleanType = null; |
| | | |
| | | //The keyword of a simple bind rule. |
| | | private EnumBindRuleKeyword keyword = null; |
| | | |
| | | //Regular expression stuff that needs to be made clearer. |
| | | private static final int keywordPos = 1; |
| | | private static final int opPos = 2; |
| | | private static final int expressionPos = 3; |
| | | private static final String keywordRegex = "^(\\w+)"; |
| | | private static final String opRegex = "([!=<>]+)"; |
| | | private static final String expressionRegex = "\"([^\"]+)\"\\s*"; |
| | | private static final String bindruleRegex = |
| | | keywordRegex + "\\s*" + opRegex + "\\s*" + expressionRegex; |
| | | private static final int remainingOperandPos = 1; |
| | | private static final int remainingBindrulePos = 2; |
| | | private static final String remainingBindruleRegex = |
| | | "^\\s*(\\w+)\\s*(.*)$"; |
| | | |
| | | /** |
| | | * Constructor that takes an keyword enumeration and corresponding |
| | | * simple bind rule. The keyword string is the key for the keyword rule in |
| | | * the keywordRuleMap. This is a simple bind rule representation: |
| | | |
| | | * keyword op rule |
| | | * |
| | | * An example of a simple bind rule is: |
| | | * |
| | | * userdn = "ldap:///anyone" |
| | | * |
| | | * @param keyword The keyword enumeration. |
| | | * @param rule The rule corresponding to this keyword. |
| | | */ |
| | | private BindRule(EnumBindRuleKeyword keyword, KeywordBindRule rule) { |
| | | this.keyword=keyword; |
| | | this.keywordRuleMap.put(keyword.toString(), rule); |
| | | } |
| | | |
| | | |
| | | /* |
| | | * TODO Verify that this handles the NOT boolean properly by |
| | | * creating a unit test. |
| | | * |
| | | * I'm a bit confused by the constructor which takes left and right |
| | | * arguments. Is it always supposed to have exactly two elements? |
| | | * Is it supposed to keep nesting bind rules in a chain until all of |
| | | * them have been processed? The documentation for this method needs |
| | | * to be a lot clearer. Also, it doesn't look like it handles the NOT |
| | | * type properly. |
| | | */ |
| | | /** |
| | | * Constructor that represents a complex bind rule. The left and right |
| | | * bind rules are saved along with the boolean type operator. A complex |
| | | * bind rule looks like: |
| | | * |
| | | * bindrule booleantype bindrule |
| | | * |
| | | * Each side of the complex bind rule can be complex bind rule(s) |
| | | * itself. An example of a complex bind rule would be: |
| | | * |
| | | * (dns="*.example.com" and (userdn="ldap:///anyone" or |
| | | * (userdn="ldap:///cn=foo,dc=example,dc=com and ip=129.34.56.66))) |
| | | * |
| | | * This constructor should always have two elements. The processing |
| | | * of a complex bind rule is dependent on the boolean operator type. |
| | | * See the evalComplex method for more information. |
| | | * |
| | | * |
| | | * @param left The bind rule left of the boolean. |
| | | * @param right The right bind rule. |
| | | * @param booleanType The boolean type enumeration ("and" or "or"). |
| | | */ |
| | | private BindRule(BindRule left, BindRule right, |
| | | EnumBooleanTypes booleanType) { |
| | | this.booleanType = booleanType; |
| | | this.left = left; |
| | | this.right = right; |
| | | } |
| | | |
| | | /* |
| | | * TODO Verify this method handles escaped parentheses by writing |
| | | * a unit test. |
| | | * |
| | | * It doesn't look like the decode() method handles the possibility of |
| | | * escaped parentheses in a bind rule. |
| | | */ |
| | | /** |
| | | * Decode an ACI bind rule string representation. |
| | | * @param input The string representation of the bind rule. |
| | | * @return A BindRule class representing the bind rule. |
| | | * @throws AciException If the string is an invalid bind rule. |
| | | */ |
| | | public static BindRule decode (String input) |
| | | throws AciException { |
| | | if ((input == null) || (input.length() == 0)) |
| | | { |
| | | return null; |
| | | } |
| | | String bindruleStr = input.trim(); |
| | | char firstChar = bindruleStr.charAt(0); |
| | | char[] bindruleArray = bindruleStr.toCharArray(); |
| | | |
| | | if (firstChar == '(') |
| | | { |
| | | BindRule bindrule_1 = null; |
| | | int currentPos; |
| | | int numOpen = 0; |
| | | int numClose = 0; |
| | | |
| | | // Find the associated closed parenthesis |
| | | for (currentPos = 0; currentPos < bindruleArray.length; currentPos++) |
| | | { |
| | | if (bindruleArray[currentPos] == '(') |
| | | { |
| | | numOpen++; |
| | | } |
| | | else if (bindruleArray[currentPos] == ')') |
| | | { |
| | | numClose++; |
| | | } |
| | | if (numClose == numOpen) |
| | | { |
| | | //We found the associated closed parenthesis |
| | | //the parenthesis are removed |
| | | String bindruleStr1 = bindruleStr.substring(1, currentPos); |
| | | bindrule_1 = BindRule.decode(bindruleStr1); |
| | | break; |
| | | } |
| | | } |
| | | /* |
| | | * Check that the number of open parenthesis is the same as |
| | | * the number of closed parenthesis. |
| | | * Raise an exception otherwise. |
| | | */ |
| | | if (numOpen > numClose) { |
| | | int msgID = MSGID_ACI_SYNTAX_BIND_RULE_MISSING_CLOSE_PAREN; |
| | | String message = getMessage(msgID, input); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | /* |
| | | * If there are remaining chars => there MUST be an |
| | | * operand (AND / OR) |
| | | * otherwise there is a syntax error |
| | | */ |
| | | if (currentPos < (bindruleArray.length - 1)) |
| | | { |
| | | String remainingBindruleStr = |
| | | bindruleStr.substring(currentPos + 1); |
| | | return createBindRule(bindrule_1, remainingBindruleStr); |
| | | } |
| | | else |
| | | { |
| | | return bindrule_1; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | StringBuilder b=new StringBuilder(bindruleStr); |
| | | /* |
| | | * TODO Verify by unit test that this negation |
| | | * is correct. This code handles a simple bind rule negation such |
| | | * as: |
| | | * |
| | | * not userdn="ldap:///anyone" |
| | | */ |
| | | boolean negate=determineNegation(b); |
| | | bindruleStr=b.toString(); |
| | | Pattern bindrulePattern = Pattern.compile(bindruleRegex); |
| | | Matcher bindruleMatcher = bindrulePattern.matcher(bindruleStr); |
| | | int bindruleEndIndex; |
| | | if (bindruleMatcher.find()) |
| | | { |
| | | bindruleEndIndex = bindruleMatcher.end(); |
| | | BindRule bindrule_1 = parseAndCreateBindrule(bindruleMatcher); |
| | | bindrule_1.setNegate(negate); |
| | | if (bindruleEndIndex < bindruleStr.length()) |
| | | { |
| | | String remainingBindruleStr = |
| | | bindruleStr.substring(bindruleEndIndex); |
| | | return createBindRule(bindrule_1, remainingBindruleStr); |
| | | } |
| | | else { |
| | | return bindrule_1; |
| | | } |
| | | } |
| | | else { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_BIND_RULE_SYNTAX; |
| | | String message = getMessage(msgID, input); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Parses a simple bind rule using the regular expression matcher. |
| | | * @param bindruleMatcher A regular expression matcher holding |
| | | * the engine to use in the creation of a simple bind rule. |
| | | * @return A BindRule determined by the matcher. |
| | | * @throws AciException If the bind rule matcher found errors. |
| | | */ |
| | | private static BindRule parseAndCreateBindrule(Matcher bindruleMatcher) |
| | | throws AciException { |
| | | String keywordStr = bindruleMatcher.group(keywordPos); |
| | | String operatorStr = bindruleMatcher.group(opPos); |
| | | String expression = bindruleMatcher.group(expressionPos); |
| | | EnumBindRuleKeyword keyword; |
| | | EnumBindRuleType operator; |
| | | |
| | | // Get the Keyword |
| | | keyword = EnumBindRuleKeyword.createBindRuleKeyword(keywordStr); |
| | | if (keyword == null) |
| | | { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD; |
| | | String message = getMessage(msgID, keywordStr); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | |
| | | // Get the operator |
| | | operator = EnumBindRuleType.createBindruleOperand(operatorStr); |
| | | if (operator == null) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_BIND_RULE_OPERATOR; |
| | | String message = getMessage(msgID, operatorStr); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | |
| | | //expression can't be null |
| | | if (expression == null) { |
| | | int msgID = MSGID_ACI_SYNTAX_MISSING_BIND_RULE_EXPRESSION; |
| | | String message = getMessage(msgID, operatorStr); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | validateOperation(keyword, operator); |
| | | KeywordBindRule rule = decode(expression, keyword, operator); |
| | | return new BindRule(keyword, rule); |
| | | } |
| | | |
| | | /** |
| | | * Create a complex bind rule from a substring |
| | | * parsed from the ACI string. |
| | | * @param bindrule The left hand part of a complex bind rule |
| | | * parsed previously. |
| | | * @param remainingBindruleStr The string used to determine the right |
| | | * hand part. |
| | | * @return A BindRule representing a complex bind rule. |
| | | * @throws AciException If the string contains an invalid |
| | | * right hand bind rule string. |
| | | */ |
| | | private static BindRule createBindRule(BindRule bindrule, |
| | | String remainingBindruleStr) throws AciException { |
| | | Pattern remainingBindrulePattern = |
| | | Pattern.compile(remainingBindruleRegex); |
| | | Matcher remainingBindruleMatcher = |
| | | remainingBindrulePattern.matcher(remainingBindruleStr); |
| | | if (remainingBindruleMatcher.find()) { |
| | | String remainingOperand = |
| | | remainingBindruleMatcher.group(remainingOperandPos); |
| | | String remainingBindrule = |
| | | remainingBindruleMatcher.group(remainingBindrulePos); |
| | | EnumBooleanTypes operand = |
| | | EnumBooleanTypes.createBindruleOperand(remainingOperand); |
| | | if ((operand == null) |
| | | || ((operand != EnumBooleanTypes.AND_BOOLEAN_TYPE) && |
| | | (operand != EnumBooleanTypes.OR_BOOLEAN_TYPE))) { |
| | | int msgID = |
| | | MSGID_ACI_SYNTAX_INVALID_BIND_RULE_BOOLEAN_OPERATOR; |
| | | String message = getMessage(msgID, remainingOperand); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | StringBuilder ruleExpr=new StringBuilder(remainingBindrule); |
| | | /* TODO write a unit test to verify. |
| | | * This is a check for something like: |
| | | * bindrule and not (bindrule) |
| | | * or something ill-advised like: |
| | | * and not not not (bindrule). |
| | | */ |
| | | boolean negate=determineNegation(ruleExpr); |
| | | remainingBindrule=ruleExpr.toString(); |
| | | BindRule bindrule_2 = |
| | | BindRule.decode(remainingBindrule); |
| | | bindrule_2.setNegate(negate); |
| | | return new BindRule(bindrule, bindrule_2, operand); |
| | | } else { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_BIND_RULE_SYNTAX; |
| | | String message = getMessage(msgID, remainingBindruleStr); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Tries to strip an "not" boolean modifier from the string and |
| | | * determine at the same time if the value should be flipped. |
| | | * For example: |
| | | * |
| | | * not not not bindrule |
| | | * |
| | | * is true. |
| | | * |
| | | * @param ruleExpr The bindrule expression to evaluate. This |
| | | * string will be changed if needed. |
| | | * @return True if the boolean needs to be negated. |
| | | */ |
| | | private static boolean determineNegation(StringBuilder ruleExpr) { |
| | | boolean negate=false; |
| | | String ruleStr=ruleExpr.toString(); |
| | | while(ruleStr.regionMatches(true, 0, "not ", 0, 4)) { |
| | | negate = !negate; |
| | | ruleStr = ruleStr.substring(4); |
| | | } |
| | | ruleExpr.replace(0, ruleExpr.length(), ruleStr); |
| | | return negate; |
| | | } |
| | | |
| | | /** |
| | | * Set the negation parameter as determined by the function above. |
| | | * @param v The value to assign negate to. |
| | | */ |
| | | private void setNegate(boolean v) { |
| | | negate=v; |
| | | } |
| | | |
| | | /* |
| | | * TODO This method needs to handle the userattr keyword. Also verify |
| | | * that the rest of the keywords are handled correctly. |
| | | * TODO Investigate moving this method into EnumBindRuleKeyword class. |
| | | * |
| | | * Does validateOperation need a default case? Why is USERATTR not in this |
| | | * list? Why is TIMEOFDAY not in this list when DAYOFWEEK is in the list? |
| | | * Would it be more appropriate to put this logic in the |
| | | * EnumBindRuleKeyword class so we can be sure it's always handled properly |
| | | * for all keywords? |
| | | */ |
| | | /** |
| | | * Checks the keyword operator enumeration to make sure it is valid. |
| | | * This method doesn't handle all cases. |
| | | * @param keyword The keyword enumeration to evaluate. |
| | | * @param op The operation enumeration to evaluate. |
| | | * @throws AciException If the operation is not valid for the keyword. |
| | | */ |
| | | private static void validateOperation(EnumBindRuleKeyword keyword, |
| | | EnumBindRuleType op) |
| | | throws AciException { |
| | | switch (keyword) { |
| | | case USERDN: |
| | | case ROLEDN: |
| | | case GROUPDN: |
| | | case IP: |
| | | case DNS: |
| | | case AUTHMETHOD: |
| | | case DAYOFWEEK: |
| | | if ((op != EnumBindRuleType.EQUAL_BINDRULE_TYPE) |
| | | && (op != EnumBindRuleType.NOT_EQUAL_BINDRULE_TYPE)) { |
| | | int msgID = |
| | | MSGID_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD_OPERATOR_COMBO; |
| | | String message = getMessage(msgID, |
| | | keyword.toString(), |
| | | op.toString()); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /* |
| | | * TODO Investigate moving into the EnumBindRuleKeyword class. |
| | | * |
| | | * Should we move the logic in the |
| | | * decode(String,EnumBindRuleKeyword,EnumBindRuleType) method into the |
| | | * EnumBindRuleKeyword class so we can be sure that it's always |
| | | * handled properly for all keywords? |
| | | */ |
| | | /** |
| | | * Creates a keyword bind rule suitable for saving in the keyword |
| | | * rule map table. Each individual keyword class will do further |
| | | * parsing and validation of the expression string. This processing |
| | | * is part of the simple bind rule creation. |
| | | * @param expr The expression string to further parse. |
| | | * @param keyword The keyword to create. |
| | | * @param op The operation part of the bind rule. |
| | | * @return A keyword bind rule class that can be stored in the |
| | | * map table. |
| | | * @throws AciException If the expr string contains a invalid |
| | | * bind rule. |
| | | */ |
| | | private static KeywordBindRule decode(String expr, |
| | | EnumBindRuleKeyword keyword, |
| | | EnumBindRuleType op) |
| | | throws AciException { |
| | | KeywordBindRule rule; |
| | | switch (keyword) { |
| | | case USERDN: |
| | | { |
| | | rule = UserDN.decode(expr, op); |
| | | break; |
| | | } |
| | | case ROLEDN: |
| | | { |
| | | rule = RoleDN.decode(expr, op); |
| | | break; |
| | | } |
| | | case GROUPDN: |
| | | { |
| | | rule = GroupDN.decode(expr, op); |
| | | break; |
| | | } |
| | | case IP: |
| | | { |
| | | rule = IpCriteria.decode(expr, op); |
| | | break; |
| | | } |
| | | case DNS: |
| | | { |
| | | rule = DNS.decode(expr, op); |
| | | break; |
| | | } |
| | | case DAYOFWEEK: |
| | | { |
| | | rule = DayOfWeek.decode(expr, op); |
| | | break; |
| | | } |
| | | case TIMEOFDAY: |
| | | { |
| | | rule=TimeOfDay.decode(expr, op); |
| | | break; |
| | | } |
| | | case AUTHMETHOD: |
| | | { |
| | | rule = AuthMethod.decode(expr, op); |
| | | break; |
| | | } |
| | | case USERATTR: |
| | | { |
| | | rule = UserAttr.decode(expr, op); |
| | | break; |
| | | } |
| | | default: { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD; |
| | | String message = getMessage(msgID, keyword.toString()); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } |
| | | return rule; |
| | | } |
| | | |
| | | /** |
| | | * Evaluate the results of a complex bind rule. If the boolean |
| | | * is an AND type then left and right must be TRUE, else |
| | | * it must be an OR result and one of the bind rules must be |
| | | * TRUE. |
| | | * @param left The left bind rule result to evaluate. |
| | | * @param right The right bind result to evaluate. |
| | | * @return The result of the complex evaluation. |
| | | */ |
| | | private EnumEvalResult evalComplex(EnumEvalResult left, |
| | | EnumEvalResult right) { |
| | | EnumEvalResult ret=EnumEvalResult.FALSE; |
| | | if(booleanType == EnumBooleanTypes.AND_BOOLEAN_TYPE) { |
| | | if((left == EnumEvalResult.TRUE) && (right == EnumEvalResult.TRUE)) |
| | | ret=EnumEvalResult.TRUE; |
| | | } else if((left == EnumEvalResult.TRUE) || |
| | | (right == EnumEvalResult.TRUE)) |
| | | ret=EnumEvalResult.TRUE; |
| | | return ret; |
| | | } |
| | | |
| | | /** |
| | | * Evaluate an bind rule against an evaluation context. If it is a simple |
| | | * bind rule (no boolean type) then grab the keyword rule from the map |
| | | * table and call the corresponding evaluate function. If it is a |
| | | * complex rule call the routine above "evalComplex()". |
| | | * @param evalCtx The evaluation context to pass to the keyword |
| | | * evaluation function. |
| | | * @return An result enumeration containing the result of the evaluation. |
| | | */ |
| | | public EnumEvalResult evaluate(AciEvalContext evalCtx) { |
| | | EnumEvalResult ret; |
| | | //Simple bind rules have a null booleanType enumeration. |
| | | if(this.booleanType == null) { |
| | | KeywordBindRule rule=keywordRuleMap.get(keyword.toString()); |
| | | ret = rule.evaluate(evalCtx); |
| | | } else |
| | | ret=evalComplex(left.evaluate(evalCtx),right.evaluate(evalCtx)); |
| | | return EnumEvalResult.negateIfNeeded(ret, negate); |
| | | } |
| | | } |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import java.util.LinkedList; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | | /** |
| | | * This class implements the dns bind rule keyword. |
| | | */ |
| | | public class DNS implements KeywordBindRule { |
| | | |
| | | LinkedList<String> patterns=null; |
| | | private EnumBindRuleType type=null; |
| | | |
| | | /** |
| | | * Create a class representing a dns bind rule keyword. |
| | | * @param patterns List of dns patterns to match against. |
| | | * @param type An enumeration representing the bind rule type. |
| | | */ |
| | | private DNS(LinkedList<String> patterns, EnumBindRuleType type) { |
| | | this.patterns=patterns; |
| | | this.type=type; |
| | | } |
| | | |
| | | /** |
| | | * Decode an string representing a dns bind rule. |
| | | * @param expr A string representation of the bind rule. |
| | | * @param type An enumeration representing the bind rule type. |
| | | * @return A keyword bind rule class that can be used to evaluate |
| | | * this bind rule. |
| | | * @throws AciException If the expression string is invalid. |
| | | */ |
| | | public static DNS decode(String expr, EnumBindRuleType type) |
| | | throws AciException |
| | | { |
| | | String valueRegex = "([a-zA-Z0-9\\.\\-\\*]+)"; |
| | | String valuesRegex = valueRegex + "\\s*(,\\s*" + valueRegex + ")*"; |
| | | if (!Pattern.matches(valuesRegex, expr)) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_DNS_EXPRESSION; |
| | | String message = getMessage(msgID, expr); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | LinkedList<String>dns=new LinkedList<String>(); |
| | | int valuePos = 1; |
| | | Pattern valuePattern = Pattern.compile(valueRegex); |
| | | Matcher valueMatcher = valuePattern.matcher(expr); |
| | | while (valueMatcher.find()) { |
| | | String hn=valueMatcher.group(valuePos); |
| | | String[] hnArray=hn.split("\\.", -1); |
| | | for(int i=1, n=hnArray.length; i < n; i++) { |
| | | if(hnArray[i].equals("*")) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_DNS_WILDCARD; |
| | | String message = getMessage(msgID, expr); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } |
| | | dns.add(hn); |
| | | } |
| | | return new DNS(dns, type); |
| | | } |
| | | |
| | | /** |
| | | * Performs evaluation of dns keyword bind rule using the provided |
| | | * evaluation context. |
| | | * @param evalCtx An evaluation context to use in the evaluation. |
| | | * @return An enumeration evaluation result. |
| | | */ |
| | | public EnumEvalResult evaluate(AciEvalContext evalCtx) { |
| | | EnumEvalResult matched=EnumEvalResult.FALSE; |
| | | String[] remoteHost = evalCtx.getHostName().split("\\.", -1); |
| | | for(String p : patterns) { |
| | | String[] pat = p.split("\\.", -1); |
| | | if(evalHostName(remoteHost, pat)) { |
| | | matched=EnumEvalResult.TRUE; |
| | | break; |
| | | } |
| | | } |
| | | return matched.getRet(type, false); |
| | | } |
| | | |
| | | /* |
| | | * TODO Verify that a DNS pattern of "*" is valid by writing a unit |
| | | * test. Probably isn't. |
| | | * |
| | | * TODO Evaluate if extending the wild-card matching to multiple name |
| | | * components should be supported. Currently wild-cards are only permitted |
| | | * in the leftmost field and the rest of the domain name components must |
| | | * match. |
| | | * |
| | | * TODO Evaluate extending wild-card matching to non-complete name matching. |
| | | * |
| | | * Is it acceptable to have a DNS address of just "*" |
| | | * (which presumably will match any system)? |
| | | * |
| | | * Is it acceptable for a wildcard to match multiple name components? For |
| | | * example, is "*.example.com" supposed to be considered a match for |
| | | * "host.east.example.com"? Similarly, would a pattern like |
| | | * "www.*.example.com" match "www.newyork.east.example.com"? It doesn't |
| | | * appear that the current implementation matches either of them. |
| | | * |
| | | * Is it acceptable for a wildcard to appear as anything other than a |
| | | * complete name component? For example, if I have three web servers |
| | | * "www1.example.com","www2.example.com", and "www3.example.com", then |
| | | * can I use "www*.example.com"? It doesn't appear that the current |
| | | * implementation allows that. Further, would "www*.example.com" match |
| | | * cases like "www.example.com" or "www1.east.example.com"? |
| | | */ |
| | | /** |
| | | * Checks an array containing the remote client's hostname against |
| | | * patterns specified in the bind rule expression. Wild-cards are |
| | | * only permitted in the leftmost field and the rest of the domain |
| | | * name array components must match. |
| | | * @param remoteHostName Array containing components of the remote clients |
| | | * hostname (split on "."). |
| | | * @param pat An array containing the pattern specified in |
| | | * the bind rule expression. The first array slot may be a wild-card "*". |
| | | * @return True if the remote hostname matches the pattern. |
| | | */ |
| | | private boolean evalHostName(String[] remoteHostName, String[] pat) { |
| | | if(remoteHostName.length != pat.length) |
| | | return false; |
| | | for(int i=0;i<remoteHostName.length;i++) |
| | | { |
| | | if(!pat[i].equals("*")) { |
| | | if(!pat[i].equalsIgnoreCase(remoteHostName[i])) |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | } |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import java.util.Calendar; |
| | | import java.util.GregorianCalendar; |
| | | import java.util.LinkedList; |
| | | |
| | | /** |
| | | * This class implements the dayofweek bind rule keyword. |
| | | */ |
| | | public class DayOfWeek implements KeywordBindRule { |
| | | |
| | | LinkedList<EnumDayOfWeek> days=null; |
| | | private EnumBindRuleType type=null; |
| | | |
| | | /** |
| | | * Create a class representing a dayofweek bind rule keyword. |
| | | * @param days A list of day of the week enumerations. |
| | | * @param type An enumeration representing the bind rule type. |
| | | */ |
| | | private DayOfWeek(LinkedList<EnumDayOfWeek> days, EnumBindRuleType type) { |
| | | this.days=days; |
| | | this.type=type; |
| | | } |
| | | |
| | | /** |
| | | * Decode an string representing a dayofweek bind rule. |
| | | * @param expr A string representation of the bind rule. |
| | | * @param type An enumeration representing the bind rule type. |
| | | * @return A keyword bind rule class that can be used to evaluate |
| | | * this bind rule. |
| | | * @throws AciException If the expression string is invalid. |
| | | */ |
| | | public static KeywordBindRule decode(String expr, EnumBindRuleType type) |
| | | throws AciException |
| | | { |
| | | LinkedList<EnumDayOfWeek>days=new LinkedList<EnumDayOfWeek>(); |
| | | String[] dayArray=expr.split(",", -1); |
| | | for(int i=0, m=dayArray.length; i < m; i++) |
| | | { |
| | | EnumDayOfWeek day=EnumDayOfWeek.createDayOfWeek(dayArray[i]); |
| | | if (day == null) |
| | | { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_DAYOFWEEK; |
| | | String message = getMessage(msgID, expr); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | days.add(day); |
| | | } |
| | | return new DayOfWeek(days, type); |
| | | } |
| | | |
| | | /** |
| | | * Performs evaluation of a dayofweek bind rule using the provided |
| | | * evaluation context. |
| | | * @param evalCtx An evaluation context to use in the evaluation. |
| | | * @return An enumeration evaluation result. |
| | | */ |
| | | public EnumEvalResult evaluate(AciEvalContext evalCtx) { |
| | | EnumEvalResult matched=EnumEvalResult.FALSE; |
| | | GregorianCalendar calendar = new GregorianCalendar(); |
| | | EnumDayOfWeek dayofweek |
| | | = EnumDayOfWeek.getDayOfWeek(calendar.get(Calendar.DAY_OF_WEEK)); |
| | | if(days.contains(dayofweek)) |
| | | matched=EnumEvalResult.TRUE; |
| | | return matched.getRet(type, false); |
| | | } |
| | | } |
| 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 two access |
| | | * types (allow, deny). |
| | | */ |
| | | public enum EnumAccessType { |
| | | /** |
| | | * Allow access type. |
| | | */ |
| | | ALLOW ("allow"), |
| | | /** |
| | | * Deny access type. |
| | | */ |
| | | DENY ("deny"); |
| | | |
| | | private final String accessType; |
| | | |
| | | /** |
| | | * Constructor that sets the accessType string. |
| | | * @param accessType The access type string to set. |
| | | */ |
| | | EnumAccessType (String accessType){ |
| | | this.accessType = accessType ; |
| | | } |
| | | |
| | | /** |
| | | * Checks if the access type is equal to the string |
| | | * representation passed in. |
| | | * @param type The string representation of the access type. |
| | | * @return True if the access types are equal. |
| | | */ |
| | | public boolean isAccessType(String type){ |
| | | return type.equalsIgnoreCase(accessType); |
| | | } |
| | | |
| | | /* |
| | | * TODO Make this method and all other Enum decode methods more efficient. |
| | | * |
| | | * Using the Enum.values() method is documented to be potentially slow. |
| | | * If we ever expect to use the decode() method in a performance-critical |
| | | * manner, then we should make it more efficient. The same thing applies |
| | | * to all of the other enumeration types defined in the package. |
| | | */ |
| | | /** |
| | | * Decodes an access type enumeration from a string passed into the method. |
| | | * @param type The string representation of the access type. |
| | | * @return Return an EnumAccessType matching the string representation, |
| | | * or null if the string is not valid. |
| | | */ |
| | | public static EnumAccessType decode(String type){ |
| | | if (type != null){ |
| | | for (EnumAccessType t : EnumAccessType.values()) { |
| | | if (t.isAccessType(type)){ |
| | | return t; |
| | | } |
| | | } |
| | | } |
| | | 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; |
| | | /* |
| | | * TODO Evaluate moving this to a non-enumeration class that can add |
| | | * SASL mechanisms dynamically. |
| | | * |
| | | * Given our previous discussion about needing to support any kind of SASL |
| | | * mechanism that may be registered with the server, perhaps an enum isn't |
| | | * the right way to handle this because we don't know ahead of time what |
| | | * auth methods might be available (certainly not at compile time, but |
| | | * potentially not even at runtime since I can add support for a new SASL |
| | | * mechanism on the fly without restarting the server). |
| | | */ |
| | | /** |
| | | * This class provides an enumeration of the allowed authmethod types. |
| | | */ |
| | | public enum EnumAuthMethod { |
| | | /** |
| | | * The enumeration type when the bind rule has specified authentication of |
| | | * none. |
| | | */ |
| | | AUTHMETHOD_NONE ("none"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified authentication of |
| | | * simple. |
| | | */ |
| | | AUTHMETHOD_SIMPLE ("simple"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified authentication of |
| | | * ssl client auth. |
| | | */ |
| | | AUTHMETHOD_SSL ("ssl"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified authentication of |
| | | * sasl DIGEST-MD5. |
| | | */ |
| | | AUTHMETHOD_SASL_MD5 ("sasl DIGEST-MD5"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified authentication of |
| | | * sasl EXTERNAL. |
| | | */ |
| | | AUTHMETHOD_SASL_EXTERNAL ("sasl EXTERNAL"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified authentication of |
| | | * sasl GSSAPI. |
| | | */ |
| | | AUTHMETHOD_SASL_GSSAPI ("sasl GSSAPI"), |
| | | /** |
| | | * Special internal enumeration for when there is no match. |
| | | */ |
| | | AUTHMETHOD_NOMATCH ("nomatch"); |
| | | |
| | | /** |
| | | * The name of the authmethod. |
| | | */ |
| | | public String authmethod = null; |
| | | |
| | | /** |
| | | * Creates a new enumeration type for this authmethod. |
| | | * @param authmethod The authemethod name. |
| | | */ |
| | | EnumAuthMethod (String authmethod){ |
| | | this.authmethod = authmethod; |
| | | } |
| | | |
| | | /** |
| | | * Checks if a authmethod name is equal to this enumeration. |
| | | * @param myauthmethod The name to test for. |
| | | * @return True if the names match. |
| | | */ |
| | | public boolean isAuthMethod(String myauthmethod){ |
| | | return myauthmethod.equalsIgnoreCase(this.authmethod); |
| | | } |
| | | |
| | | /** |
| | | * Creates an authmethod enumeration from the name passed in. |
| | | * @param myauthmethod The name to create. |
| | | * @return An authmethod enumeration if the name was found or null if not. |
| | | */ |
| | | public static EnumAuthMethod createAuthmethod(String myauthmethod){ |
| | | if (myauthmethod != null){ |
| | | for (EnumAuthMethod t : EnumAuthMethod.values()){ |
| | | if (t.isAuthMethod(myauthmethod)){ |
| | | return t; |
| | | } |
| | | } |
| | | } |
| | | 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; |
| | | |
| | | /** |
| | | * This class provides an enumeration of the allowed bind rule |
| | | * keyword types. |
| | | */ |
| | | public enum EnumBindRuleKeyword { |
| | | /** |
| | | * The enumeration type when the bind rule has specified keyword of |
| | | * userdn. |
| | | */ |
| | | USERDN ("userdn"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified keyword of |
| | | * groupdn. |
| | | */ |
| | | GROUPDN ("groupdn"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified keyword of |
| | | * roledn. |
| | | */ |
| | | ROLEDN ("roledn"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified keyword of |
| | | * ip. |
| | | */ |
| | | IP ("ip"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified keyword of |
| | | * dns. |
| | | */ |
| | | DNS ("dns"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified keyword of |
| | | * dayofweek. |
| | | */ |
| | | DAYOFWEEK ("dayofweek"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified keyword of |
| | | * timeofday. |
| | | */ |
| | | TIMEOFDAY ("timeofday"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified keyword of |
| | | * userattr. |
| | | */ |
| | | USERATTR ("userattr"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified keyword of |
| | | * authmethod. |
| | | */ |
| | | AUTHMETHOD ("authmethod"); |
| | | /** |
| | | * The keyword name. |
| | | */ |
| | | public final String keyword; |
| | | |
| | | /** |
| | | * Creates a new enumeration type for the specified keyword. |
| | | * @param keyword The keyword name. |
| | | */ |
| | | EnumBindRuleKeyword(String keyword){ |
| | | this.keyword = keyword; |
| | | } |
| | | |
| | | /** |
| | | * Checks to see if the keyword string is equal to the enumeration. |
| | | * @param keywordStr The keyword name to check equality for. |
| | | * @return True if the keyword is equal to the specified name. |
| | | */ |
| | | public boolean isBindRuleKeyword(String keywordStr){ |
| | | return keywordStr.equalsIgnoreCase(this.keyword); |
| | | } |
| | | |
| | | /** |
| | | * Create a new enumeration type for the specified keyword name. |
| | | * @param keywordStr The name of the enumeration to create. |
| | | * @return A new enumeration type for the name or null if the name is |
| | | * not valid. |
| | | */ |
| | | public static EnumBindRuleKeyword createBindRuleKeyword(String keywordStr){ |
| | | if (keywordStr != null){ |
| | | for (EnumBindRuleKeyword t : EnumBindRuleKeyword.values()){ |
| | | if (t.isBindRuleKeyword(keywordStr)){ |
| | | return t; |
| | | } |
| | | } |
| | | } |
| | | 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; |
| | | |
| | | /** |
| | | * This class provides an enumeration of the allowed bind rule types. |
| | | */ |
| | | public enum EnumBindRuleType { |
| | | /** |
| | | * The enumeration type when the bind rule has specified type of |
| | | * "=". |
| | | */ |
| | | EQUAL_BINDRULE_TYPE ("="), |
| | | /** |
| | | * The enumeration type when the bind rule has specified type of |
| | | * "!=". |
| | | */ |
| | | NOT_EQUAL_BINDRULE_TYPE ("!="), |
| | | /** |
| | | * The enumeration type when the bind rule has specified type of |
| | | * "<". |
| | | */ |
| | | LESS_BINDRULE_TYPE ("<"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified type of |
| | | * "<=". |
| | | */ |
| | | LESS_OR_EQUAL_BINDRULE_TYPE ("<="), |
| | | /** |
| | | * The enumeration type when the bind rule has specified type of |
| | | * >". |
| | | */ |
| | | GREATER_BINDRULE_TYPE (">"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified type of |
| | | * ">=". |
| | | */ |
| | | GREATER_OR_EQUAL_BINDRULE_TYPE (">="); |
| | | |
| | | /** |
| | | * The bind rule type name. |
| | | */ |
| | | private final String type; |
| | | |
| | | /** |
| | | * Creates a new enumeration type for the specified bind rule type. |
| | | * @param type The bind rule type name. |
| | | */ |
| | | EnumBindRuleType(String type){ |
| | | this.type = type; |
| | | } |
| | | |
| | | /** |
| | | * Checks to see if the type string is equal to the enumeration type |
| | | * name. |
| | | * @param type The type name to check equality for. |
| | | * @return True if the keyword is equal to the specified name. |
| | | */ |
| | | public boolean isBindRuleType(String type){ |
| | | return type.equals(this.type); |
| | | } |
| | | |
| | | /** |
| | | * Create a new enumeration type for the specified type name. |
| | | * @param type The name of the enumeration to create. |
| | | * @return A new enumeration type for the name or null if the name is |
| | | * not valid. |
| | | */ |
| | | public static EnumBindRuleType createBindruleOperand(String type){ |
| | | if (type != null){ |
| | | for (EnumBindRuleType t : EnumBindRuleType.values()){ |
| | | if (t.isBindRuleType(type)){ |
| | | return t; |
| | | } |
| | | } |
| | | } |
| | | 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; |
| | | |
| | | /** |
| | | * This class provides an enumeration of the allowed bind rule booelan types. |
| | | */ |
| | | public enum EnumBooleanTypes { |
| | | /** |
| | | * The enumeration type when the bind rule has specified boolean type of |
| | | * "AND". |
| | | */ |
| | | AND_BOOLEAN_TYPE ("and"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified boolean type of |
| | | * "OR". |
| | | */ |
| | | OR_BOOLEAN_TYPE ("or"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified boolean type of |
| | | * "NOT". |
| | | */ |
| | | NOT_BOOLEAN_TYPE ("not"); |
| | | |
| | | /** |
| | | * The bind rule boolean type name. |
| | | */ |
| | | private final String booleanType; |
| | | |
| | | /** |
| | | * Creates a new enumeration type for the specified bind rule boolean type. |
| | | * @param booleanType The boolean type name. |
| | | */ |
| | | EnumBooleanTypes(String booleanType){ |
| | | this.booleanType = booleanType; |
| | | } |
| | | |
| | | /** |
| | | * Checks to see if the boolean type string is equal to the enumeration type |
| | | * name. |
| | | * @param booleanType The type name to check equality for. |
| | | * @return True if the keyword is equal to the specified name. |
| | | */ |
| | | public boolean isBindRuleBooleanOperand(String booleanType){ |
| | | return booleanType.equalsIgnoreCase(this.booleanType); |
| | | } |
| | | |
| | | /** |
| | | * Create a new enumeration type for the specified boolean type name. |
| | | * @param booleanType The name of the enumeration to create. |
| | | * @return A new enumeration type for the name or null if the name is |
| | | * not valid. |
| | | */ |
| | | public static |
| | | EnumBooleanTypes createBindruleOperand(String booleanType) { |
| | | if (booleanType != null){ |
| | | for (EnumBooleanTypes t : EnumBooleanTypes.values()) { |
| | | if (t.isBindRuleBooleanOperand(booleanType)) { |
| | | return t; |
| | | } |
| | | } |
| | | } |
| | | 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 java.util.Calendar; |
| | | |
| | | /** |
| | | * This class provides an enumeration of the allowed dayofweek types. |
| | | */ |
| | | public enum EnumDayOfWeek { |
| | | /** |
| | | * The enumeration type when the bind rule has specified dayofweek type of |
| | | * "mon". |
| | | */ |
| | | DAY_MONDAY ("mon"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified dayofweek type of |
| | | * "tue" . |
| | | */ |
| | | DAY_TUESDAY ("tue"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified dayofweek type of |
| | | * "wed". |
| | | */ |
| | | DAY_WEDNESDAY ("wed"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified dayofweek type of |
| | | * "thu". |
| | | */ |
| | | DAY_THURSDAY ("thu"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified dayofweek type of |
| | | * "fri". |
| | | */ |
| | | DAY_FRIDAY ("fri"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified dayofweek type of |
| | | * "sat". |
| | | */ |
| | | DAY_SATURDAY ("sat"), |
| | | /** |
| | | * The enumeration type when the bind rule has specified dayofweek type of |
| | | * "sun". |
| | | */ |
| | | DAY_SUNDAY ("sun"); |
| | | |
| | | /** |
| | | * The bind rule dayofweek type name. |
| | | */ |
| | | private String day = null; |
| | | |
| | | /** |
| | | * Creates a new enumeration type for the specified bind rule dayofweek |
| | | * type. |
| | | * @param day The day name. |
| | | */ |
| | | EnumDayOfWeek (String day){ |
| | | this.day = day; |
| | | } |
| | | |
| | | /** |
| | | * Creates a new enumeration type for the specified bind rule dayofweek |
| | | * type. |
| | | * @param day The boolean type name. |
| | | * @return True if the keyword is equal to the specified name. |
| | | */ |
| | | public boolean isDayOfWeek(String day){ |
| | | return day.equalsIgnoreCase(this.day); |
| | | } |
| | | |
| | | /** |
| | | * Create a new enumeration type for the specified dayofweek type name. |
| | | * @param day The name of the enumeration to create. |
| | | * @return A new enumeration type for the name or null if the name is |
| | | * not valid. |
| | | */ |
| | | public static EnumDayOfWeek createDayOfWeek(String day) |
| | | { |
| | | if (day != null){ |
| | | for (EnumDayOfWeek t : EnumDayOfWeek.values()){ |
| | | if (t.isDayOfWeek(day)){ |
| | | return t; |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /* |
| | | * TODO Evaluate supporting alternative forms for days of the week. |
| | | * |
| | | * Should we support alternate forms for the names of the days of the |
| | | * week in the isDayOfWeek() or createdayOfWeek() method? In particular, |
| | | * should we handle the case in which the user provided the full name |
| | | * (e.g., "monday" instead of "mon")? |
| | | */ |
| | | /** |
| | | * Return a enumeration relating to a Calendar day of week field. |
| | | * @param day The day of week index to get. |
| | | * @return An enumeration corresponding to the wanted day of the week or |
| | | * null if the day index is invalid. |
| | | */ |
| | | public static EnumDayOfWeek getDayOfWeek(int day) |
| | | { |
| | | switch(day){ |
| | | case Calendar.SUNDAY: |
| | | return DAY_SUNDAY; |
| | | |
| | | case Calendar.MONDAY: |
| | | return DAY_MONDAY; |
| | | |
| | | case Calendar.TUESDAY: |
| | | return DAY_TUESDAY; |
| | | |
| | | case Calendar.WEDNESDAY: |
| | | return DAY_WEDNESDAY; |
| | | |
| | | case Calendar.THURSDAY: |
| | | return DAY_THURSDAY; |
| | | |
| | | case Calendar.FRIDAY: |
| | | return DAY_FRIDAY; |
| | | |
| | | case Calendar.SATURDAY: |
| | | return DAY_SATURDAY; |
| | | } |
| | | 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; |
| | | |
| | | /** |
| | | * This class provides an enumeration of evaluation results returned by |
| | | * the bind rule evaluation methods. |
| | | */ |
| | | public enum EnumEvalResult { |
| | | /** |
| | | * This enumeration is returned when the result of the evaluation is TRUE. |
| | | */ |
| | | TRUE(0), |
| | | /** |
| | | * This enumeration is returned when the result of the evaluation is FALSE. |
| | | */ |
| | | FALSE(1), |
| | | /** |
| | | * This enumeration is returned when the result of the evaluation is FAIL. |
| | | * This should only be returned when a system failure occurred. |
| | | */ |
| | | FAIL(2), |
| | | /** |
| | | * This is an internal enumeration used during evaluation of bind rule when |
| | | * internal processing of the evaluation is undefined. It is never returned |
| | | * back as a result of the evaluation. |
| | | */ |
| | | ERR(3); |
| | | |
| | | /** |
| | | * Create a new enumeration type for the specified result value. |
| | | * @param v The value of the result. |
| | | */ |
| | | EnumEvalResult(int v) { |
| | | } |
| | | |
| | | /** |
| | | * The method tries to determine if the result was undefined, and if so |
| | | * it returns an FAIL enumeration. If the result was not undefined (the |
| | | * common case for all of the bind rule evaluations), then the bind rule |
| | | * type is examined to see if the result needs to be flipped (type equals |
| | | * NOT_EQUAL_BINDRULE_TYPE). |
| | | * @param type The bind rule type enumeration of the bind rule. |
| | | * @param undefined A flag that signals the the result was undefined. |
| | | * @return An enumeration containing the correct result after processing |
| | | * the undefined field and the bind rule type enumeration. |
| | | */ |
| | | public EnumEvalResult getRet(EnumBindRuleType type, boolean undefined) { |
| | | EnumEvalResult ret=this; |
| | | if(this.equals(EnumEvalResult.TRUE) || !undefined) { |
| | | if(type.equals(EnumBindRuleType.NOT_EQUAL_BINDRULE_TYPE)) |
| | | if(this.equals(EnumEvalResult.TRUE)) |
| | | ret=EnumEvalResult.FALSE; |
| | | else |
| | | ret=EnumEvalResult.TRUE; |
| | | } else |
| | | ret=EnumEvalResult.FAIL; |
| | | return ret; |
| | | } |
| | | |
| | | /** |
| | | * This method is used to possibly negate the result of a simple bind rule |
| | | * evaluation. If the boolean is true than the result is negated. |
| | | * @param v The enumeration result of the simple bind rule evaluation. |
| | | * @param n If true the result should be negated (TRUE->FALSE, FALSE->TRUE). |
| | | * @return A possibly negated enumeration result. |
| | | */ |
| | | public static EnumEvalResult negateIfNeeded(EnumEvalResult v, boolean n) { |
| | | if(n) { |
| | | if(v.equals(EnumEvalResult.TRUE)) |
| | | v=EnumEvalResult.FALSE; |
| | | else |
| | | v=EnumEvalResult.TRUE; |
| | | } |
| | | return v; |
| | | } |
| | | |
| | | /** |
| | | * Helper method that converts this enumeration to a boolean. Usually the |
| | | * FAIL enumeration has been handled before this is called. |
| | | * @return True if the enumeration is TRUE, else false. |
| | | */ |
| | | public boolean getBoolVal() { |
| | | return this == EnumEvalResult.TRUE; |
| | | } |
| | | } |
| 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 allowed rights. |
| | | */ |
| | | public enum EnumRight { |
| | | |
| | | /** |
| | | * This enumeration is returned when the result of the right is "read". |
| | | */ |
| | | READ ("read"), |
| | | /** |
| | | * This enumeration is returned when the result of the right is "write". |
| | | */ |
| | | WRITE ("write"), |
| | | /** |
| | | * This enumeration is returned when the result of the right is "add". |
| | | */ |
| | | ADD ("add"), |
| | | /** |
| | | * This enumeration is returned when the result of the right is "delete". |
| | | */ |
| | | DELETE ("delete"), |
| | | /** |
| | | * This enumeration is returned when the result of the right is "search". |
| | | */ |
| | | SEARCH ("search"), |
| | | /** |
| | | * This enumeration is returned when the result of the right is "compare". |
| | | */ |
| | | COMPARE ("compare"), |
| | | /** |
| | | * This enumeration is returned when the result of the right is |
| | | * "selfwrite". |
| | | */ |
| | | SELFWRITE ("selfwrite"), |
| | | /** |
| | | * This enumeration is returned when the result of the right is "proxy". |
| | | */ |
| | | PROXY ("proxy"), |
| | | /** |
| | | * This enumeration is returned when the result of the right is "import". |
| | | */ |
| | | IMPORT ("import"), |
| | | /** |
| | | * This enumeration is returned when the result of the right is "export". |
| | | */ |
| | | EXPORT ("export"), |
| | | /** |
| | | * This enumeration is returned when the result of the right is "all". |
| | | */ |
| | | ALL ("all"), |
| | | /** |
| | | * This enumeration is used internally by the modify operation |
| | | * processing and is not part of the ACI syntax. |
| | | */ |
| | | DELWRITE ("delwrite"), |
| | | /** |
| | | * This enumerations is used internally by the modify operation |
| | | * processing and is not part of the ACI syntax. |
| | | */ |
| | | ADDWRITE ("addwrite"); |
| | | |
| | | /** |
| | | * The name of the right. |
| | | */ |
| | | private final String right; |
| | | |
| | | /** |
| | | * Creates an enumeration of the right name. |
| | | * @param right The name of the right. |
| | | */ |
| | | EnumRight (String right) { |
| | | this.right = right ; |
| | | } |
| | | |
| | | /** |
| | | * Checks if the enumeration is equal to the right name. |
| | | * @param right The name of the right to check. |
| | | * @return True if the right is equal to the enumeration's. |
| | | */ |
| | | public boolean isRight(String right){ |
| | | return right.equalsIgnoreCase(this.right); |
| | | } |
| | | |
| | | /** |
| | | * Creates an enumeration of the right name. |
| | | * @param right The name of the right. |
| | | * @return An enumeration of the right or null if the name is invalid. |
| | | */ |
| | | public static EnumRight decode(String right){ |
| | | if (right != null){ |
| | | for (EnumRight t : EnumRight.values()){ |
| | | if (t.isRight(right)){ |
| | | return t; |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * Returns bit mask associated with the specified right. |
| | | * @param right The right enumeration to return the mask for. |
| | | * @return The bit mask associated with the right. |
| | | */ |
| | | public static int getMask(EnumRight right) { |
| | | int mask=AciHandler.ACI_NULL; |
| | | switch(right) { |
| | | case READ: |
| | | mask=AciHandler.ACI_READ; |
| | | break; |
| | | case WRITE: |
| | | mask=AciHandler.ACI_WRITE; |
| | | break; |
| | | case ADD: |
| | | mask=AciHandler.ACI_ADD; |
| | | break; |
| | | case DELETE: |
| | | mask=AciHandler.ACI_DELETE; |
| | | break; |
| | | case SEARCH: |
| | | mask=AciHandler.ACI_SEARCH; |
| | | break; |
| | | case COMPARE: |
| | | mask=AciHandler.ACI_COMPARE; |
| | | break; |
| | | case ALL: |
| | | mask=AciHandler.ACI_ALL; |
| | | break; |
| | | case EXPORT: |
| | | mask=AciHandler.ACI_EXPORT; |
| | | break; |
| | | case IMPORT: |
| | | mask=AciHandler.ACI_IMPORT; |
| | | break; |
| | | case PROXY: |
| | | mask=AciHandler.ACI_PROXY; |
| | | break; |
| | | case SELFWRITE: |
| | | mask=AciHandler.ACI_SELF; |
| | | break; |
| | | } |
| | | return mask; |
| | | } |
| | | } |
| 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 valid ACI target keywords. |
| | | */ |
| | | public enum EnumTargetKeyword { |
| | | /** |
| | | * This enumeration is returned when the target keyword is |
| | | * "target". |
| | | */ |
| | | KEYWORD_TARGET ("target"), |
| | | /** |
| | | * This enumeration is returned when the target keyword is |
| | | * "targetattr". |
| | | */ |
| | | KEYWORD_TARGETATTR ("targetattr"), |
| | | /** |
| | | * This enumeration is returned when the target keyword is |
| | | * "targetscope". |
| | | */ |
| | | KEYWORD_TARGETSCOPE ("targetscope"), |
| | | /** |
| | | * This enumeration is returned when the target keyword is |
| | | * "targetfilter". |
| | | */ |
| | | KEYWORD_TARGETFILTER ("targetfilter"), |
| | | /** |
| | | * This enumeration is returned when the target keyword is |
| | | * "targattrfilters". |
| | | */ |
| | | KEYWORD_TARGATTRFILTERS ("targattrfilters"); |
| | | /* |
| | | * TODO Add support for the targattrfilters keyword. |
| | | */ |
| | | /** |
| | | * The target keyword name. |
| | | */ |
| | | private final String keyword; |
| | | |
| | | /** |
| | | * Create a target keyword enumeration of the specified name. |
| | | * @param keyword The keyword name. |
| | | */ |
| | | EnumTargetKeyword(String keyword){ |
| | | this.keyword = keyword; |
| | | } |
| | | |
| | | /** |
| | | * Checks if the keyword name is equal to the enumeration name. |
| | | * @param keyword The keyword name to check. |
| | | * @return True if the keyword name is equal to the enumeration. |
| | | */ |
| | | public boolean isKeyword(String keyword){ |
| | | return keyword.equalsIgnoreCase(this.keyword); |
| | | } |
| | | |
| | | /** |
| | | * Create an enumeration of the provided keyword name. |
| | | * @param keyword The keyword name to create. |
| | | * @return An enumeration of the specified keyword name or null |
| | | * if the keyword name is invalid. |
| | | */ |
| | | public static EnumTargetKeyword createKeyword(String keyword){ |
| | | if (keyword != null){ |
| | | for (EnumTargetKeyword t : EnumTargetKeyword.values()){ |
| | | if (t.isKeyword(keyword)){ |
| | | return t; |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * Return the enumeration keyword name. |
| | | * @return The keyword name. |
| | | */ |
| | | public String getKeyword() { |
| | | return keyword; |
| | | } |
| | | } |
| 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 valid ACI target operators. |
| | | */ |
| | | public enum EnumTargetOperator { |
| | | /** |
| | | * This enumeration is returned when the target operator is "=". |
| | | */ |
| | | EQUALITY ("="), |
| | | /** |
| | | * This enumeration is returned when the target operator is "!=". |
| | | */ |
| | | NOT_EQUALITY ("!="); |
| | | |
| | | /** |
| | | * The target operator name. |
| | | */ |
| | | private final String operator; |
| | | |
| | | /** |
| | | * Create an enumeration of the provided operator name. |
| | | * @param operator The operator name to create. |
| | | */ |
| | | EnumTargetOperator(String operator){ |
| | | this.operator = operator; |
| | | } |
| | | |
| | | /** |
| | | * Checks if the provided operator name is equal to the enumeration. |
| | | * @param op The operator name to check for. |
| | | * @return True if the operator name is equal to the enumeration. |
| | | */ |
| | | public boolean isOperator(String op){ |
| | | return op.equalsIgnoreCase(operator); |
| | | } |
| | | |
| | | /** |
| | | * Creates an enumeration of the specified operator type name. |
| | | * @param op The operator type name to create. |
| | | * @return Return an enumeration of the operator type name or null if the |
| | | * name is invalid. |
| | | */ |
| | | public static EnumTargetOperator createOperator(String op){ |
| | | if (op != null){ |
| | | for (EnumTargetOperator t : EnumTargetOperator.values()){ |
| | | if (t.isOperator(op)){ |
| | | return t; |
| | | } |
| | | } |
| | | } |
| | | 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; |
| | | |
| | | |
| | | /** |
| | | * Enumeration that represents the type an "userdn" keyword DN can have. |
| | | * The issues is the syntax allows invalid URLs such as "ldap:///anyone" |
| | | * and "ldap:///self". The strategy is to use this class to hold |
| | | * the type and another class UserDNTypeURL to hold both this type and URL. |
| | | * |
| | | * If the URL is an invalid URL, then a dummy URL is saved. |
| | | * For types such as URL, DN and DNPATTERN, the actual URL is saved and can |
| | | * be retrieved by the UserDN.evaluate() method when needed. The dummy URL is |
| | | * ignored in the UserDN.evaluate() method for types such as: ALL, PARENT, |
| | | * SELF and ANYONE. |
| | | */ |
| | | public enum EnumUserDNType { |
| | | /** |
| | | * The enumeration type when the "userdn" URL contains only a DN (no |
| | | * filter or scope) and that DN has no pattern. |
| | | */ |
| | | DN(0), |
| | | /** |
| | | * The enumeration type when the "userdn" URL contains only a DN (no |
| | | * filter or scope) and that DN has a substring pattern. |
| | | */ |
| | | DNPATTERN(1), |
| | | /** |
| | | * The enumeration type when the "userdn" URL has the value of: |
| | | * "ldap:///all". |
| | | */ |
| | | ALL(2), |
| | | /** |
| | | * The enumeration type when the "userdn" URL has the value of: |
| | | * "ldap:///parent". |
| | | */ |
| | | PARENT(3), |
| | | /** |
| | | * The enumeration type when the "userdn" URL has the value of: |
| | | * "ldap:///self". |
| | | */ |
| | | SELF(4), |
| | | /** |
| | | * The enumeration type when the "userdn" URL has the value of: |
| | | * "ldap:///anyone". |
| | | */ |
| | | ANYONE(5), |
| | | /** |
| | | * The enumeration type when the "userdn" URL is contains a DN (suffix), |
| | | * a scope and a filter. |
| | | */ |
| | | URL(6); |
| | | |
| | | /** |
| | | * Constructor taking an integer value. |
| | | * @param v Integer value. |
| | | */ |
| | | EnumUserDNType(int v) {} |
| | | } |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import org.opends.server.types.*; |
| | | import org.opends.server.api.Group; |
| | | import org.opends.server.core.GroupManager; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import java.util.Iterator; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | | |
| | | /** |
| | | * This class implements the groupdn bind rule keyword. |
| | | */ |
| | | public class GroupDN implements KeywordBindRule { |
| | | |
| | | LinkedList<DN> groupDNs=null; |
| | | private EnumBindRuleType type=null; |
| | | private static GroupManager groupManager = |
| | | DirectoryServer.getGroupManager(); |
| | | |
| | | /** |
| | | * Create a class representing a groupdn bind rule keyword. |
| | | * @param type An enumeration representing the bind rule type. |
| | | * @param groupDNs A list of the dns representing groups. |
| | | */ |
| | | private GroupDN(EnumBindRuleType type, LinkedList<DN> groupDNs ) { |
| | | this.groupDNs=groupDNs; |
| | | this.type=type; |
| | | } |
| | | |
| | | /** |
| | | * Decode an string expression representing a groupdn bind rule. |
| | | * @param expr A string representation of the bind rule. |
| | | * @param type An enumeration of the type of the bind rule. |
| | | * @return A keyword bind rule class that can be used to evaluate |
| | | * this bind rule. |
| | | * @throws AciException If the expression string is invalid. |
| | | */ |
| | | public static KeywordBindRule decode(String expr, EnumBindRuleType type) |
| | | throws AciException { |
| | | String ldapURLRegex = "\\s*(ldap:///[^\\|]+)"; |
| | | String ldapURLSRegex = |
| | | ldapURLRegex + "\\s*(\\|\\|\\s*" + ldapURLRegex + ")*"; |
| | | if (!Pattern.matches(ldapURLSRegex, expr)) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_GROUPDN_EXPRESSION; |
| | | String message = getMessage(msgID, expr); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | LinkedList<DN>groupDNs=new LinkedList<DN>(); |
| | | int ldapURLPos = 1; |
| | | Pattern ldapURLPattern = Pattern.compile(ldapURLRegex); |
| | | Matcher ldapURLMatcher = ldapURLPattern.matcher(expr); |
| | | while (ldapURLMatcher.find()) { |
| | | try { |
| | | String value = ldapURLMatcher.group(ldapURLPos).trim(); |
| | | DN dn=LDAPURL.decode(value, true).getBaseDN(); |
| | | groupDNs.add(dn); |
| | | } catch (DirectoryException ex) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_GROUPDN_URL; |
| | | String message = getMessage(msgID, ex.getErrorMessage()); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } |
| | | return new GroupDN(type, groupDNs); |
| | | } |
| | | |
| | | /** |
| | | * Performs the evaluation of a groupdn bind rule based on the |
| | | * evaluation context passed to it. The evaluation stops when there |
| | | * are no more group DNs to evaluate, or if a group DN evaluates to true |
| | | * if it contains the client DN. |
| | | * @param evalCtx An evaluation context to use in the evaluation. |
| | | * @return Enumeration evaluation result. |
| | | */ |
| | | public EnumEvalResult evaluate(AciEvalContext evalCtx) { |
| | | EnumEvalResult matched = EnumEvalResult.FALSE; |
| | | Iterator<DN> it=groupDNs.iterator(); |
| | | for(; it.hasNext() && matched != EnumEvalResult.TRUE;) { |
| | | DN groupDN=it.next(); |
| | | Group group = groupManager.getGroupInstance(groupDN); |
| | | if((group != null) && (evalCtx.isMemberOf(group))) |
| | | matched = EnumEvalResult.TRUE; |
| | | } |
| | | return matched.getRet(type, false); |
| | | } |
| | | |
| | | /** |
| | | * Performs an evaluation of a group that was specified in an attribute |
| | | * type value of the specified entry and attribute type. Each |
| | | * value of the attribute type is assumed to be a group DN and evaluation |
| | | * stops when there are no more values or if the group DN evaluates to |
| | | * true if it contains the client DN. |
| | | * @param e The entry to use in the evaluation. |
| | | * @param evalCtx The evaluation context to use in the evaluation. |
| | | * @param attributeType The attribute type of the entry to use to get the |
| | | * values for the groupd DNs. |
| | | * @return Enumeration evaluation result. |
| | | */ |
| | | public static EnumEvalResult evaluate (Entry e, AciEvalContext evalCtx, |
| | | AttributeType attributeType) { |
| | | EnumEvalResult matched= EnumEvalResult.FALSE; |
| | | List<Attribute> attrs = e.getAttribute(attributeType); |
| | | LinkedHashSet<AttributeValue> vals = attrs.get(0).getValues(); |
| | | for(AttributeValue v : vals) { |
| | | try { |
| | | DN groupDN=DN.decode(v.getStringValue()); |
| | | Group group = groupManager.getGroupInstance(groupDN); |
| | | if((group != null) && (evalCtx.isMemberOf(group))) { |
| | | matched=EnumEvalResult.TRUE; |
| | | break; |
| | | } |
| | | } catch (DirectoryException ex) { |
| | | break; |
| | | } |
| | | } |
| | | return matched; |
| | | } |
| | | } |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import java.net.Inet6Address; |
| | | import java.net.InetAddress; |
| | | import java.net.UnknownHostException; |
| | | |
| | | /** |
| | | * This class builds a network string to an internal representation. |
| | | */ |
| | | public class IpBitsNetworkCriteria { |
| | | |
| | | byte[] _address; // address in byte format |
| | | int _bits; // number of bits for matching |
| | | byte[] _bitsArray; // bits in network order |
| | | InetAddress _inetAddress; |
| | | |
| | | /** |
| | | * Creates a new IpBitsNeworkCriteria instance. |
| | | * |
| | | * @param theInputAddress IP address associated the rule. For IPV4 |
| | | * addresses, the following |
| | | * textual formats are supported |
| | | * a.b.c.d |
| | | * a.b.c |
| | | * a.b |
| | | * a |
| | | * For IPv6 addresses, the following textual |
| | | * format are supported: |
| | | * x:x:x:x:x:x:x:x, where x are the hexadecimal |
| | | * values of the 8 |
| | | * 16-bits pieces of the address |
| | | * Use of :: to compress the leading |
| | | * and/or trailing zeros e.g. |
| | | * x::x:x:x:x:x:x |
| | | * |
| | | * @param theBits Number of bits of the network address |
| | | * necessary for matching. |
| | | * Max is 32 for IPv4 addresses and 128 |
| | | * for IPv6 addresses \ |
| | | * |
| | | * @throws UnknownHostException Thrown if the inetaddress cannot be gotten |
| | | * from the input address string. |
| | | * @throws AciException Thrown if the bit count is not in the correct |
| | | * ranges. |
| | | */ |
| | | |
| | | public IpBitsNetworkCriteria(String theInputAddress, int theBits) |
| | | throws UnknownHostException, AciException |
| | | { |
| | | boolean ipv4 = true; |
| | | _inetAddress = InetAddress.getByName(theInputAddress); |
| | | |
| | | if (_inetAddress instanceof Inet6Address) |
| | | { |
| | | if (theBits < 0 || theBits > 128) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_NETWORK_BIT_MATCH; |
| | | String message = getMessage(msgID, "IPV6", |
| | | "Bits must be in [0..128] range."); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | ipv4=false; |
| | | } |
| | | else |
| | | { |
| | | // Assume IPv4 |
| | | if (theBits < 0 || theBits > 32) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_NETWORK_BIT_MATCH; |
| | | String message = getMessage(msgID, "IPV4", |
| | | "Bits must be in [0..32] range."); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } |
| | | |
| | | _bits = theBits; |
| | | |
| | | // Convert the bits into a mask in network byte order |
| | | if (ipv4) |
| | | { |
| | | _bitsArray = new byte[4]; |
| | | // in java int is exactly 4 bytes |
| | | int rawBits; |
| | | if (theBits==0) |
| | | rawBits=0; |
| | | else |
| | | rawBits=~0; |
| | | rawBits = rawBits << (32 - theBits); |
| | | // Use network order for the comparison |
| | | _bitsArray[0] = (byte) ((rawBits >> 24) & 0xFF ); |
| | | _bitsArray[1] = (byte) ((rawBits >> 16) & 0xFF ); |
| | | _bitsArray[2] = (byte) ((rawBits >> 8) & 0xFF ); |
| | | _bitsArray[3] = (byte) ((rawBits) & 0xFF ); |
| | | } |
| | | else |
| | | { |
| | | _bitsArray = new byte[16]; |
| | | int index=0; |
| | | if (theBits > 64) |
| | | { |
| | | _bitsArray[0] = (byte) 0xFF; |
| | | _bitsArray[1] = (byte) 0xFF; |
| | | _bitsArray[2] = (byte) 0xFF; |
| | | _bitsArray[3] = (byte) 0xFF; |
| | | _bitsArray[4] = (byte) 0xFF; |
| | | _bitsArray[5] = (byte) 0xFF; |
| | | _bitsArray[6] = (byte) 0xFF; |
| | | _bitsArray[7] = (byte) 0xFF; |
| | | theBits-=64; |
| | | index=8; |
| | | } |
| | | long rawBits = ~0; |
| | | rawBits = rawBits << (64 - theBits); |
| | | |
| | | if (_bits !=0) |
| | | { |
| | | _bitsArray[index++] = (byte) ((rawBits >> 56) & 0xFF ); |
| | | _bitsArray[index++] = (byte) ((rawBits >> 48) & 0xFF ); |
| | | _bitsArray[index++] = (byte) ((rawBits >> 40) & 0xFF ); |
| | | _bitsArray[index++] = (byte) ((rawBits >> 32) & 0xFF ); |
| | | _bitsArray[index++] = (byte) ((rawBits >> 24) & 0xFF ); |
| | | _bitsArray[index++] = (byte) ((rawBits >> 16) & 0xFF ); |
| | | _bitsArray[index++] = (byte) ((rawBits >> 8) & 0xFF ); |
| | | _bitsArray[index] = (byte) ((rawBits ) & 0xFF ); |
| | | } |
| | | } |
| | | |
| | | _address = _inetAddress.getAddress(); |
| | | } |
| | | |
| | | /** |
| | | * Compare an IP address with the network rule. |
| | | * |
| | | * @param theSourceAddress IP source address of the client contacting |
| | | * the proxy server. |
| | | * @return <CODE>true</CODE> if client matches the network rule or |
| | | * <CODE>false</CODE> if they may not. |
| | | */ |
| | | |
| | | public boolean match (InetAddress theSourceAddress) |
| | | { |
| | | |
| | | byte[] addr = theSourceAddress.getAddress(); |
| | | |
| | | if ((addr.length * 8) < _bits) { |
| | | // Client IP too small. Won't match. |
| | | return false; |
| | | } |
| | | |
| | | for (int i=0; i<addr.length; i++) |
| | | { |
| | | if ((addr[i] & _bitsArray[i]) != (_address[i] & _bitsArray[i])) { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | return true; |
| | | |
| | | } |
| | | |
| | | /** |
| | | * String representation of this criteria. |
| | | * |
| | | * @return a String representation of the IpMaskNetworkCriteria |
| | | */ |
| | | |
| | | public String toString() |
| | | { |
| | | return "Address:" + _inetAddress.getHostAddress() + |
| | | "/" + Integer.toString(_bits); |
| | | } |
| | | |
| | | } |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import java.net.Inet6Address; |
| | | import java.net.InetAddress; |
| | | import java.net.UnknownHostException; |
| | | import java.util.HashSet; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | | /** |
| | | * This class represents a ip bind rule keyword. |
| | | */ |
| | | public class IpCriteria implements KeywordBindRule |
| | | { |
| | | private EnumBindRuleType type=null; |
| | | |
| | | // private token to express that any address is accepted |
| | | private final static String ANY_ADDRESSES = "ALL"; |
| | | private boolean matchAnyAddress = false; |
| | | |
| | | private IpBitsNetworkCriteria[] ipBitsCriteria = null; |
| | | private IpMaskNetworkCriteria[] ipMaskCriteria = null; |
| | | |
| | | /* |
| | | * TODO Verifiy IpCriteria constructor adheres to DS 5.2 ip keyword |
| | | * syntax. |
| | | * |
| | | * Based on the contents of the constructor, it doesn't appear that the |
| | | * IpCriteria class uses the same set of allowed values as DS 5.2 does |
| | | * with the "ip" keyword (as documented at |
| | | * http://docs.sun.com/source/817-7613/aci.html#wp20242). Was that the |
| | | * intention? It looks like it doesn't allow asterisks as wild-ccards or |
| | | * plus signs to specify netmasks (although it appears that it expects a |
| | | * slash to be used if you want a netmask). While I don't mind allowing |
| | | * alternate formats (e.g., CIDR-style addresses), we can't drop support |
| | | * for the existing ones if we're trying to maintain compatibility. |
| | | */ |
| | | /** |
| | | * Constructor that creates an IpCriteria from an array of values and |
| | | * an enumeration bind rule type. |
| | | * @param values An array of address values. |
| | | * @param type An enumeration of the bind rule type. |
| | | * @throws UnknownHostException If the host address cannot be resolved to |
| | | * a hostname. |
| | | * @throws AciException If a part of the address is invalid. |
| | | * @throws IndexOutOfBoundsException If an index is incremented past an |
| | | * array bounds when copying or evaluating an address. |
| | | */ |
| | | public IpCriteria(String[] values, EnumBindRuleType type) |
| | | throws UnknownHostException, IndexOutOfBoundsException, AciException { |
| | | IpBitsNetworkCriteria[] ipBitsCriteria_2 = null; |
| | | IpMaskNetworkCriteria[] ipMaskCriteria_2 = null; |
| | | try |
| | | { |
| | | for (String value : values) |
| | | { |
| | | if (value.equalsIgnoreCase(ANY_ADDRESSES)) |
| | | { |
| | | matchAnyAddress = true; |
| | | continue; |
| | | } |
| | | // determine what format it is to instantiate |
| | | // the right criteria object |
| | | int slash = value.indexOf("/"); |
| | | if (slash == -1) |
| | | { |
| | | // simple raw IP address |
| | | IpBitsNetworkCriteria newInstance; |
| | | if (InetAddress.getByName(value) |
| | | instanceof Inet6Address) |
| | | { |
| | | newInstance = new IpBitsNetworkCriteria(value, 128); |
| | | } else |
| | | { |
| | | newInstance = new IpBitsNetworkCriteria(value, 32); |
| | | } |
| | | if (ipBitsCriteria_2 == null) |
| | | { |
| | | ipBitsCriteria_2 = new IpBitsNetworkCriteria[1]; |
| | | } else |
| | | { |
| | | IpBitsNetworkCriteria[] newIpBitsCriteria = |
| | | new IpBitsNetworkCriteria[ipBitsCriteria_2.length + 1]; |
| | | System.arraycopy(ipBitsCriteria_2, 0, |
| | | newIpBitsCriteria, 0, ipBitsCriteria_2.length); |
| | | ipBitsCriteria_2 = newIpBitsCriteria; |
| | | } |
| | | ipBitsCriteria_2[ipBitsCriteria_2.length - 1] = newInstance; |
| | | } else |
| | | { |
| | | // Extract data following the / and figure out whether it |
| | | // is a bit number or a mask |
| | | try |
| | | { |
| | | int bits = |
| | | Integer.parseInt(value.substring(slash + 1)); |
| | | // Well, no exception, so this is a bit |
| | | // Let's instantiate the corresponding criterion |
| | | if (ipBitsCriteria_2 == null) |
| | | { |
| | | ipBitsCriteria_2 = new IpBitsNetworkCriteria[1]; |
| | | } else |
| | | { |
| | | IpBitsNetworkCriteria[] newIpBitsCriteria = |
| | | new IpBitsNetworkCriteria[ipBitsCriteria_2.length + 1]; |
| | | System.arraycopy(ipBitsCriteria_2, 0, |
| | | newIpBitsCriteria, 0, ipBitsCriteria_2.length); |
| | | ipBitsCriteria_2 = newIpBitsCriteria; |
| | | } |
| | | ipBitsCriteria_2[ipBitsCriteria_2.length - 1] = |
| | | new IpBitsNetworkCriteria(value. |
| | | substring(0, slash), bits); |
| | | } |
| | | catch (IndexOutOfBoundsException e1) |
| | | { |
| | | throw e1; |
| | | } |
| | | catch (Exception e2) |
| | | { |
| | | // Looks like this is a network mask. |
| | | if (ipMaskCriteria_2 == null) |
| | | { |
| | | ipMaskCriteria_2 = new IpMaskNetworkCriteria[1]; |
| | | } else |
| | | { |
| | | IpMaskNetworkCriteria[] newIpMaskCriteria = |
| | | new IpMaskNetworkCriteria[ipMaskCriteria_2.length + 1]; |
| | | System.arraycopy(ipMaskCriteria_2, 0, |
| | | newIpMaskCriteria, 0, ipMaskCriteria_2.length); |
| | | ipMaskCriteria_2 = newIpMaskCriteria; |
| | | } |
| | | try |
| | | { |
| | | ipMaskCriteria_2[ipMaskCriteria_2.length - 1] = |
| | | new IpMaskNetworkCriteria(value. |
| | | substring(0, slash), value.substring(slash + 1)); |
| | | } |
| | | catch (IndexOutOfBoundsException e3) |
| | | { |
| | | throw e3; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | catch (UnknownHostException ue) |
| | | { |
| | | throw ue; |
| | | } |
| | | ipBitsCriteria = ipBitsCriteria_2; |
| | | ipMaskCriteria = ipMaskCriteria_2; |
| | | this.type=type; |
| | | } |
| | | |
| | | /** |
| | | * Return the ipBitsNetworkCriteria of this IpCriteria. |
| | | * @return Returns the ipBitsNetworkCriteria. |
| | | */ |
| | | public IpBitsNetworkCriteria[] getIpBitsNetworkCriteria() { |
| | | return ipBitsCriteria; |
| | | } |
| | | |
| | | /** |
| | | * Return the ipMaskNetworkCriteria of this IpCriteria. |
| | | * @return Returns the ipMaskNetworkCriteria. |
| | | */ |
| | | public IpMaskNetworkCriteria[] getIpMaskNetworkCriteria() { |
| | | return ipMaskCriteria; |
| | | } |
| | | |
| | | /** |
| | | * Compare an IP address with the network rule. |
| | | * |
| | | * @param theSourceAddress IP source address of the client. |
| | | * @return <CODE>true</CODE> if client matches the network rule or |
| | | * <CODE>false</CODE> if they may not. |
| | | */ |
| | | public boolean match (InetAddress theSourceAddress) |
| | | { |
| | | if (matchAnyAddress){ |
| | | return true; |
| | | } |
| | | if (ipMaskCriteria != null) |
| | | { |
| | | for (IpMaskNetworkCriteria anIpMaskCriteria : ipMaskCriteria) |
| | | { |
| | | if (anIpMaskCriteria.match(theSourceAddress)) |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (ipBitsCriteria != null) |
| | | { |
| | | for (IpBitsNetworkCriteria anIpBitsCriteria : ipBitsCriteria) |
| | | { |
| | | if (anIpBitsCriteria.match(theSourceAddress)) |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return (ipBitsCriteria == null) && (ipMaskCriteria == null); |
| | | } |
| | | |
| | | /** |
| | | * Decode an expression string representing a ip keyword bind rule |
| | | * expression. |
| | | * @param expr A string representing the expression. |
| | | * @param type An enumeration representing the bind rule type. |
| | | * @return An keyword bind rule that can be used to evaluate the |
| | | * expression. |
| | | * @throws AciException If the expression string is invalid. |
| | | */ |
| | | public static KeywordBindRule decode(String expr, EnumBindRuleType type) |
| | | throws AciException { |
| | | String valueRegex = "([^,\\s]+)"; |
| | | String valuesRegex = valueRegex + "\\s*(,\\s*" + valueRegex + ")*"; |
| | | if (!Pattern.matches(valuesRegex, expr)) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_IP_EXPRESSION; |
| | | String message = getMessage(msgID, expr); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | |
| | | int valuePos = 1; |
| | | Pattern valuePattern = Pattern.compile(valueRegex); |
| | | Matcher valueMatcher = valuePattern.matcher(expr); |
| | | HashSet<String> values = new HashSet<String>(); |
| | | while (valueMatcher.find()) { |
| | | String value = valueMatcher.group(valuePos); |
| | | values.add(value); |
| | | } |
| | | IpCriteria ipCriteria; |
| | | String[] strValues = null; |
| | | if (!values.isEmpty()) { |
| | | strValues = values.toArray(new String[values.size()]); |
| | | } |
| | | try { |
| | | ipCriteria = new IpCriteria(strValues, type); |
| | | } catch (Exception e) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_IP_CRITERIA_DECODE; |
| | | String message = getMessage(msgID, e.getMessage()); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | return ipCriteria; |
| | | } |
| | | |
| | | /** |
| | | * Evaluate the evaluation context against this ip criteria. |
| | | * @param evalCtx An evaluation context to use. |
| | | * @return An enumeration evaluation result. |
| | | */ |
| | | public EnumEvalResult evaluate(AciEvalContext evalCtx) { |
| | | EnumEvalResult matched=EnumEvalResult.FALSE; |
| | | if(match(evalCtx.getRemoteAddress())) |
| | | matched=EnumEvalResult.TRUE; |
| | | return matched.getRet(type, false); |
| | | } |
| | | } |
| | | |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import java.net.Inet4Address; |
| | | import java.net.Inet6Address; |
| | | import java.net.InetAddress; |
| | | import java.net.UnknownHostException; |
| | | |
| | | /** |
| | | * This class creates a network mask criteria from the address and mask |
| | | * string passed to it. |
| | | */ |
| | | class IpMaskNetworkCriteria |
| | | { |
| | | |
| | | byte[] _address; // address in byte format |
| | | byte[] _mask; // mask in byte format |
| | | InetAddress _inetAddress; |
| | | InetAddress _inetMask; |
| | | boolean _ipv4; // true if ipv4 address |
| | | |
| | | |
| | | /** |
| | | * Creates a new IpMaskNeworkCriteria instance. |
| | | * |
| | | * @param theInputAddress IP address associated the rule. For IPV4 |
| | | * addresses, the following |
| | | * textual formats are supported |
| | | * a.b.c.d |
| | | * a.b.c |
| | | * a.b |
| | | * a |
| | | * For IPv6 addresses, the following textual |
| | | * format are supported: |
| | | * x:x:x:x:x:x:x:x, where x are the hexadecimal |
| | | * values of the 8 16-bits pieces of the address |
| | | * Use of :: to compress the leading and/or |
| | | * trailing zeros e.g.x::x:x:x:x:x:x |
| | | * |
| | | * @param theInputMask Bits of the network address necessary |
| | | * for matching. |
| | | * Same format as the IP address above. |
| | | * |
| | | * @throws UnknownHostException Thrown if the hostname of the input address |
| | | * cannot be resolved. |
| | | * @throws AciException If the address family has a mismatch. |
| | | */ |
| | | |
| | | public IpMaskNetworkCriteria(String theInputAddress, String theInputMask) |
| | | throws UnknownHostException, AciException { |
| | | _inetAddress = InetAddress.getByName(theInputAddress); |
| | | _inetMask = InetAddress.getByName(theInputMask); |
| | | _address = _inetAddress.getAddress(); |
| | | _mask = _inetMask.getAddress(); |
| | | |
| | | if (_inetAddress instanceof Inet4Address) |
| | | _ipv4=true; |
| | | |
| | | if (_ipv4 && !(_inetMask instanceof Inet4Address) || |
| | | (!_ipv4 && !(_inetMask instanceof Inet6Address))) { |
| | | int msgID = MSGID_ACI_SYNTAX_ADDRESS_FAMILY_MISMATCH; |
| | | String message = getMessage(msgID, theInputMask, theInputAddress); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Compare an IP address with the network criteria. |
| | | * |
| | | * @param theSourceAddress IP source address of the client. |
| | | * @return <CODE>true</CODE> if client matches the network rule or |
| | | * <CODE>false</CODE> if they may not. |
| | | */ |
| | | |
| | | public boolean match (InetAddress theSourceAddress) |
| | | { |
| | | // First address family must match |
| | | if (_ipv4) |
| | | { |
| | | if (!(theSourceAddress instanceof Inet4Address)) |
| | | return false; |
| | | } |
| | | else |
| | | { |
| | | if (!(theSourceAddress instanceof Inet6Address)) |
| | | return false; |
| | | } |
| | | |
| | | byte[] addr = theSourceAddress.getAddress(); |
| | | for (int i=0; i<addr.length; i++) { |
| | | if ((addr[i] & _mask[i]) != (_address[i] & _mask[i])) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | |
| | | } |
| | | |
| | | /** |
| | | * String representation of this rule. |
| | | * |
| | | * @return a String representation of the IpMaskNetworkRule. |
| | | */ |
| | | |
| | | public String toString() |
| | | { |
| | | return "Address:" + _inetAddress.getHostAddress() + |
| | | " Mask:" + _inetMask.getHostAddress(); |
| | | } |
| | | } |
| | | |
| | | |
| 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 interface represents a keyword bind rule class |
| | | * that can evaluate an evaluation context. It defines a single |
| | | * function that each of the keyword functions implement (ip, dns, |
| | | * roledn, groupdn, ...) |
| | | */ |
| | | public interface KeywordBindRule |
| | | { |
| | | /** |
| | | * Evaluate a bind rule using the passed in context. |
| | | * @param evalCtx An evaluation context to use in the evaluation. |
| | | * @return An enumeration evaluation result. |
| | | */ |
| | | public EnumEvalResult evaluate(AciEvalContext evalCtx); |
| | | } |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import java.util.StringTokenizer; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.types.AttributeType; |
| | | |
| | | /** |
| | | * This class is used by USERDN and GROUPDN userattr types |
| | | * to determine what parent inheritance checks to make. |
| | | */ |
| | | public class ParentInheritance { |
| | | /* |
| | | * The maximum number of parent inheritance levels supported. |
| | | * |
| | | */ |
| | | private static final int MAX_LEVELS=10; |
| | | private String parentPat="parent["; |
| | | private int[] levels=new int[MAX_LEVELS]; |
| | | private int numLevels; |
| | | private AttributeType attributeType; |
| | | |
| | | |
| | | /** |
| | | * Construct a class from the inheritance pattern. The skipParsing boolean |
| | | * specifies that parent parsing should be skipped and sets up the class: |
| | | * with numLevels=1, level[0]=0 and an attribute type from the |
| | | * specified pattern. |
| | | * |
| | | * @param pattern The string pattern containing the inheritance |
| | | * information. |
| | | * @param skipParse Specify if the parent inheritance parsing should be |
| | | * skipped or not. |
| | | * @throws AciException If the pattern is invalid. |
| | | */ |
| | | ParentInheritance (String pattern, boolean skipParse) throws AciException { |
| | | if (skipParse) { |
| | | //The "parent[" pattern is invalid for ROLEDN user attr keyword. |
| | | if(pattern.startsWith(parentPat)) { |
| | | int msgID = |
| | | MSGID_ACI_SYNTAX_INVALID_USERATTR_ROLEDN_INHERITANCE_PATTERN; |
| | | String message = getMessage(msgID, pattern); |
| | | throw new AciException(msgID, message); |
| | | } else { |
| | | pattern=pattern.trim(); |
| | | if((this.attributeType = |
| | | DirectoryServer.getAttributeType(pattern)) == null) |
| | | this.attributeType = |
| | | DirectoryServer.getDefaultAttributeType(pattern); |
| | | numLevels=1; |
| | | levels[0]=0; |
| | | } |
| | | } else |
| | | parse(pattern); |
| | | } |
| | | |
| | | /** |
| | | * Performs all parsing of the specified pattern string. |
| | | * @param pattern The string pattern containing the inheritance |
| | | * information. |
| | | * @throws AciException If the pattern is invalid. |
| | | */ |
| | | private void parse (String pattern) throws AciException { |
| | | pattern=pattern.trim(); |
| | | /** |
| | | * Check if we have a "parent[" string. |
| | | */ |
| | | if(pattern.startsWith(parentPat)) { |
| | | numLevels=0; |
| | | levels[0]=0; |
| | | String p=pattern.substring(parentPat.length()); |
| | | /** |
| | | * Format needs to be parent[XX].attribute -- everything after the |
| | | * '.' is the attribute type. |
| | | */ |
| | | String[] toks=p.split("\\."); |
| | | if(toks.length != 2) { |
| | | int msgID = |
| | | MSGID_ACI_SYNTAX_INVALID_USERATTR_INHERITANCE_PATTERN; |
| | | String message = getMessage(msgID, pattern); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | if((this.attributeType = |
| | | DirectoryServer.getAttributeType(toks[1])) == null) |
| | | this.attributeType = |
| | | DirectoryServer.getDefaultAttributeType(toks[1]); |
| | | StringTokenizer tok=new StringTokenizer(toks[0],"],",false); |
| | | while(tok.hasMoreTokens()) { |
| | | String v=tok.nextToken(); |
| | | /** |
| | | * Everything between the brackets must be an integer or it's |
| | | * an error. |
| | | */ |
| | | try { |
| | | if(numLevels < MAX_LEVELS) { |
| | | levels[numLevels++]=Integer.decode(v); |
| | | } else { |
| | | int msgID = |
| | | MSGID_ACI_SYNTAX_MAX_USERATTR_INHERITANCE_LEVEL_EXCEEDED; |
| | | String message = getMessage(msgID, pattern, |
| | | Integer.toString(MAX_LEVELS)); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } catch (NumberFormatException ex) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_INHERITANCE_VALUE; |
| | | String message = getMessage(msgID, pattern); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } |
| | | } else { |
| | | if((this.attributeType = |
| | | DirectoryServer.getAttributeType(pattern)) == null) |
| | | this.attributeType = |
| | | DirectoryServer.getDefaultAttributeType(pattern); |
| | | numLevels=1; |
| | | levels[0]=0; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Returns the number of levels counted. |
| | | * @return The number of levels. |
| | | */ |
| | | public int getNumLevels() { |
| | | return numLevels; |
| | | } |
| | | |
| | | /** |
| | | * Returns an array of levels, where levels are integers. |
| | | * @return Return an array of levels. |
| | | */ |
| | | public int[] getLevels() { |
| | | return levels; |
| | | } |
| | | |
| | | /** |
| | | * Return the attribute type. |
| | | * @return The attribute type. |
| | | */ |
| | | public AttributeType getAttributeType() { |
| | | return attributeType; |
| | | } |
| | | } |
| | | |
| 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; |
| | | |
| | | /** |
| | | * A class representing a permission-bind rule pair. There can be multiple |
| | | * of these in an ACI. |
| | | */ |
| | | public class PermBindRulePair { |
| | | |
| | | private BindRule bindRule; |
| | | private Permission perm=null; |
| | | |
| | | /** |
| | | * This constructor calls the permission and bind rule decodes |
| | | * with the appropriate strings. |
| | | * @param perm A string representing the permissions. |
| | | * @param rights A string representing the rights. |
| | | * @param bindRule A string representing the bind rule. |
| | | * @throws AciException If any of the strings fail to decode. |
| | | */ |
| | | private PermBindRulePair(String perm, String rights, String bindRule) |
| | | throws AciException { |
| | | this.perm=Permission.decode(perm, rights); |
| | | this.bindRule=BindRule.decode(bindRule); |
| | | } |
| | | |
| | | /** |
| | | * Decodes a permission bind rule pair. |
| | | * @param perm A string representing the permissions. |
| | | * @param rights A string representing the rights. |
| | | * @param bRule A string representing the bind rule. |
| | | * @return An permission bind rule pair class representing this pair. |
| | | * @throws AciException If any of the strings fail to decode. |
| | | */ |
| | | public static PermBindRulePair decode(String perm, String rights, |
| | | String bRule) throws AciException { |
| | | return new PermBindRulePair(perm, rights, bRule); |
| | | } |
| | | |
| | | /** |
| | | * Gets the bind rule part of this pair. |
| | | * @return The bind rule part of this pair. |
| | | */ |
| | | public BindRule getBindRule () { |
| | | return bindRule; |
| | | } |
| | | |
| | | /** |
| | | * Checks the permission to see if it has this access type. |
| | | * @param accessType An enumeration of the desired access type. |
| | | * @return True if the access type equals the permission access type. |
| | | */ |
| | | public boolean hasAccessType(EnumAccessType accessType) { |
| | | return perm.hasAccessType(accessType); |
| | | } |
| | | |
| | | /** |
| | | * Try and match one or more of the specified rights against a rights set |
| | | * of the permission class. |
| | | * @param right The rights to match. |
| | | * @return True if one or more of the specified rights match a right in |
| | | * the rights set of the permission class. |
| | | */ |
| | | public boolean hasRights(int right) { |
| | | return perm.hasRights(right); |
| | | } |
| | | } |
| 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 static org.opends.server.messages.MessageHandler.getMessage; |
| | | import static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import java.util.regex.Pattern; |
| | | |
| | | /** |
| | | * A class representing the permissions of an bind rule. The permissions |
| | | * of an ACI look like deny(search, write). |
| | | */ |
| | | public class Permission { |
| | | //the access type (allow,deny) |
| | | private EnumAccessType accessType = null; |
| | | private int rights; |
| | | private static final String separatorToken = ","; |
| | | private static final String rightsRegex = |
| | | "\\s*(\\w+)\\s*(,\\s*(\\w+)\\s*)*"; |
| | | |
| | | /** |
| | | * Constructor creating a class representing a permission part of an bind |
| | | * rule. |
| | | * @param accessType A string representing access type. |
| | | * @param rights A string representing the rights. |
| | | * @throws AciException If the access type string or rights string |
| | | * is invalid. |
| | | */ |
| | | private Permission(String accessType, String rights) |
| | | throws AciException { |
| | | if ((this.accessType = |
| | | EnumAccessType.decode(accessType)) == null){ |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_ACCESS_TYPE_VERSION; |
| | | String message = getMessage(msgID, accessType); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | if (!Pattern.matches(rightsRegex, rights)){ |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_RIGHTS_SYNTAX; |
| | | String message = getMessage(msgID, rights); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | else { |
| | | Pattern separatorPattern = Pattern.compile(separatorToken); |
| | | String[] rightsStr = |
| | | separatorPattern.split(rights.replaceAll("\\s", "")); |
| | | for (String r : rightsStr) { |
| | | EnumRight right = EnumRight.decode(r); |
| | | if (right != null) |
| | | this.rights|= EnumRight.getMask(right); |
| | | else { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_RIGHTS_KEYWORD; |
| | | String message = getMessage(msgID, rights); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Decode an string representation of bind rule permission into a Permission |
| | | * class. |
| | | * @param accessType A string representing the access type. |
| | | * @param rights A string representing the rights. |
| | | * @return A Permission class representing the permissions of the bind |
| | | * rule. |
| | | * @throws AciException If the accesstype or rights strings are invalid. |
| | | */ |
| | | public static |
| | | Permission decode (String accessType, String rights) |
| | | throws AciException { |
| | | return new Permission(accessType, rights); |
| | | } |
| | | |
| | | /** |
| | | * Checks if a given access type enumeration is equal to this classes |
| | | * access type. |
| | | * @param accessType An enumeration representing an access type. |
| | | * @return True if the access types are equal. |
| | | */ |
| | | public boolean hasAccessType(EnumAccessType accessType) { |
| | | return this.accessType == accessType; |
| | | } |
| | | |
| | | /** |
| | | * Checks if the permission's rights has the specified rights. |
| | | * @param rights The rights to check for. |
| | | * @return True if the permission's rights has the specified rights. |
| | | */ |
| | | public boolean hasRights(int rights) { |
| | | return (this.rights & rights) != 0; |
| | | } |
| | | } |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import org.opends.server.types.*; |
| | | import org.opends.server.api.Group; |
| | | import org.opends.server.core.GroupManager; |
| | | import org.opends.server.core.DirectoryServer; |
| | | |
| | | import java.util.LinkedList; |
| | | import java.util.Iterator; |
| | | import java.util.List; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.regex.Pattern; |
| | | import java.util.regex.Matcher; |
| | | |
| | | /** |
| | | * A class representing a roledn bind rule keyword. This class is almost |
| | | * an exact copy of groupDN, except for variable names and error messages. |
| | | */ |
| | | public class RoleDN implements KeywordBindRule { |
| | | |
| | | LinkedList<DN> roleDNs=null; |
| | | private EnumBindRuleType type=null; |
| | | private static GroupManager groupManager = |
| | | DirectoryServer.getGroupManager(); |
| | | |
| | | /** |
| | | * Constructor creating a class representing a roledn keyword of a bind |
| | | * rule. |
| | | * @param type An enumeration of the type of the bind rule. |
| | | * @param roleDNs A list of the role dns parsed from the expression string. |
| | | */ |
| | | private RoleDN(EnumBindRuleType type, LinkedList<DN> roleDNs ) { |
| | | this.roleDNs=roleDNs; |
| | | this.type=type; |
| | | } |
| | | |
| | | /** |
| | | * Decodes an expression string representing an roledn bind rule. |
| | | * @param expr A string representation of the bind rule. |
| | | * @param type An enumeration of the type of the bind rule. |
| | | * @return A keyword bind rule class that can be used to evaluate |
| | | * this bind rule. |
| | | * @throws AciException If the expression is invalid. |
| | | */ |
| | | public static KeywordBindRule decode(String expr, EnumBindRuleType type) |
| | | throws AciException { |
| | | String ldapURLRegex = "\\s*(ldap:///[^\\|]+)"; |
| | | String ldapURLSRegex = |
| | | ldapURLRegex + "\\s*(\\|\\|\\s*" + ldapURLRegex + ")*"; |
| | | if (!Pattern.matches(ldapURLSRegex, expr)) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_ROLEDN_EXPRESSION; |
| | | String message = getMessage(msgID, expr); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | LinkedList<DN>roleDNs=new LinkedList<DN>(); |
| | | int ldapURLPos = 1; |
| | | Pattern ldapURLPattern = Pattern.compile(ldapURLRegex); |
| | | Matcher ldapURLMatcher = ldapURLPattern.matcher(expr); |
| | | while (ldapURLMatcher.find()) { |
| | | String val = ldapURLMatcher.group(ldapURLPos); |
| | | val = val.trim(); |
| | | DN dn; |
| | | try { |
| | | dn=DN.decode(val); |
| | | } catch (DirectoryException ex) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_ROLEDN_URL; |
| | | String message = getMessage(msgID, ex.getErrorMessage()); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | roleDNs.add(dn); |
| | | } |
| | | return new RoleDN(type, roleDNs); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Performs the evaluation of a roledn bind rule based on the |
| | | * evaluation context passed to it. The method uses an exact copy |
| | | * evaluation method as the groupDN.evaluate(). The evaluation stops when |
| | | * there are no more group DNs to evaluate, or if a group DN evaluates to |
| | | * true if it contains the authorization DN. |
| | | * @param evalCtx An evaluation context to use in the evaluation. |
| | | * @return Enumeration evaluation result. |
| | | */ |
| | | public EnumEvalResult evaluate(AciEvalContext evalCtx) { |
| | | EnumEvalResult matched = EnumEvalResult.FALSE; |
| | | Iterator<DN> it=roleDNs.iterator(); |
| | | for(; it.hasNext() && matched != EnumEvalResult.TRUE;) { |
| | | DN groupDN=it.next(); |
| | | Group group = groupManager.getGroupInstance(groupDN); |
| | | if(evalCtx.isMemberOf(group)) |
| | | matched = EnumEvalResult.TRUE; |
| | | } |
| | | return matched.getRet(type, false); |
| | | } |
| | | |
| | | /** |
| | | * Performs an evaluation of a group that was specified in an attribute |
| | | * type value of the specified entry and attribute type. Each |
| | | * value of the attribute type is assumed to be a group DN and evaluation |
| | | * stops when there are no more values or if the group DN evaluates to |
| | | * true if it contains the client DN. |
| | | * @param e The entry to use in the evaluation. |
| | | * @param evalCtx The evaluation context to use in the evaluation. |
| | | * @param attributeType The attribute type of the entry to use to get the |
| | | * values for the groupd DNs. |
| | | * @return Enumeration evaluation result. |
| | | */ |
| | | public static EnumEvalResult evaluate (Entry e, AciEvalContext evalCtx, |
| | | AttributeType attributeType) { |
| | | EnumEvalResult matched= EnumEvalResult.FALSE; |
| | | List<Attribute> attrs = e.getAttribute(attributeType); |
| | | LinkedHashSet<AttributeValue> vals = attrs.get(0).getValues(); |
| | | for(AttributeValue v : vals) { |
| | | try { |
| | | DN groupDN=DN.decode(v.getStringValue()); |
| | | Group group = groupManager.getGroupInstance(groupDN); |
| | | if((group != null) && (evalCtx.isMemberOf(group))) { |
| | | matched=EnumEvalResult.TRUE; |
| | | break; |
| | | } |
| | | } catch (DirectoryException ex) { |
| | | break; |
| | | } |
| | | } |
| | | return matched; |
| | | } |
| | | } |
| 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; |
| | | |
| | | /** |
| | | * Placeholder. This class is partially complete. The TargAttrFilters class |
| | | * will represent an targAttrFitlers rule. |
| | | */ |
| | | public class TargAttrFilters { |
| | | |
| | | /** |
| | | * Represents an targAttrFilters rule. |
| | | */ |
| | | public TargAttrFilters() { |
| | | |
| | | } |
| | | |
| | | /** |
| | | * Decode an string representing a targattrfilters keyword. |
| | | * @param operator The operator of the rule. |
| | | * @param expression The string parsed from the ACI representing the |
| | | * targattrfilters rule. |
| | | * @return An object representing an targattrfilters rule. |
| | | * @throws AciException if the expression string cannot be parsed. |
| | | */ |
| | | public static TargAttrFilters decode(EnumTargetOperator operator, |
| | | String expression) throws AciException { |
| | | return new TargAttrFilters(); |
| | | } |
| | | } |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import java.util.ArrayList; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.regex.Pattern; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.AttributeValue; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.LDAPURL; |
| | | import org.opends.server.types.SearchFilter; |
| | | |
| | | /** |
| | | * A class representing an ACI target keyword. |
| | | */ |
| | | public class Target |
| | | { |
| | | private EnumTargetOperator operator = EnumTargetOperator.EQUALITY; |
| | | private LDAPURL targetURL = null; |
| | | private DN urlDN=null; |
| | | private boolean isPattern=false; |
| | | private SearchFilter filter=null; |
| | | private AttributeType targetType; |
| | | |
| | | |
| | | /* |
| | | * TODO Save aciDN parameter and use it in matchesPattern re-write. |
| | | * |
| | | * Should the aciDN argument provided to the constructor be stored so that |
| | | * it can be used in the matchesPattern() method? The DN should only be |
| | | * considered a potential match if it is at or below the entry containing |
| | | * the ACI. |
| | | * |
| | | * TODO Evaluate re-writing pattern (substring) determination code. The |
| | | * current code is similar to current DS6 implementation. |
| | | * |
| | | * I'm confused by the part of the constructor that generates a search |
| | | * filter. First, there is no substring matching rule defined for the |
| | | * DN syntax in the official standard, so technically trying to perform |
| | | * substring matching against DNs is illegal. Although we do try to use |
| | | * the caseIgnoreSubstringsMatch rule, it is extremely unreliable for DNs |
| | | * because it's just not possible to do substring matching correctly in all |
| | | * cases for them. Also, the logic in place there will only generate a |
| | | * filter if the DN contains a wildcard, and if it starts with a wildcard |
| | | * (which is handled by the targetDN.startsWith("*") clause), then you'll |
| | | * end up with something like "(target=**dc=example,dc=com)", which isn't |
| | | * legal. |
| | | */ |
| | | /** |
| | | * This constructor parses the target string. |
| | | * @param operator An enumeration of the operation of this target. |
| | | * @param target A string representation of the target. |
| | | * @param aciDN The dn of the ACI entry used for a descendant check. |
| | | * @throws AciException If the target string is invalid. |
| | | */ |
| | | private Target(EnumTargetOperator operator, String target, DN aciDN) |
| | | throws AciException { |
| | | this.operator = operator; |
| | | try { |
| | | String ldapURLRegex = "\\s*(ldap:///[^\\|]+)"; |
| | | if (!Pattern.matches(ldapURLRegex, target)) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_TARGETKEYWORD_EXPRESSION; |
| | | String message = getMessage(msgID, target); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | targetURL = LDAPURL.decode(target, false); |
| | | urlDN=targetURL.getBaseDN(); |
| | | String targetDN=urlDN.toNormalizedString(); |
| | | if((targetDN.startsWith("*")) || |
| | | (targetDN.indexOf("*") != -1)) { |
| | | this.isPattern=true; |
| | | String pattern="target=*"+targetDN; |
| | | filter=SearchFilter.createFilterFromString(pattern); |
| | | targetType = DirectoryServer.getAttributeType("target"); |
| | | if (targetType == null) |
| | | targetType = |
| | | DirectoryServer.getDefaultAttributeType("target"); |
| | | } else { |
| | | if(!urlDN.isDescendantOf(aciDN)) { |
| | | int msgID = MSGID_ACI_SYNTAX_TARGET_DN_NOT_DESCENDENTOF; |
| | | String message = getMessage(msgID, |
| | | urlDN.toNormalizedString(), |
| | | aciDN.toNormalizedString()); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } |
| | | } |
| | | catch (DirectoryException e){ |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_TARGETKEYWORD_EXPRESSION; |
| | | String message = getMessage(msgID, target); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Decode an expression string representing a target keyword expression. |
| | | * @param operator An enumeration of the operation of this target. |
| | | * @param expr A string representation of the target. |
| | | * @param aciDN The DN of the ACI entry used for a descendant check. |
| | | * @return A Target class representing this target. |
| | | * @throws AciException If the expression string is invalid. |
| | | */ |
| | | public static Target decode(EnumTargetOperator operator, |
| | | String expr, DN aciDN) |
| | | throws AciException { |
| | | return new Target(operator, expr, aciDN); |
| | | } |
| | | |
| | | /** |
| | | * Returns the operator of this expression. |
| | | * @return An enumeration of the operation value. |
| | | */ |
| | | public EnumTargetOperator getOperator() { |
| | | return operator; |
| | | } |
| | | |
| | | /** |
| | | * Returns the URL DN of the expression. |
| | | * @return A DN of the URL. |
| | | */ |
| | | public DN getDN() { |
| | | return urlDN; |
| | | } |
| | | |
| | | /** |
| | | * Returns boolean if a pattern was seen during parsing. |
| | | * @return True if the DN is a wild-card. |
| | | */ |
| | | public boolean isPattern() { |
| | | return isPattern; |
| | | } |
| | | |
| | | /* |
| | | * TODO Evaluate re-writing this method. |
| | | * |
| | | * The matchesPattern() method really needs to be rewritten. It's using a |
| | | * very inefficient and very error-prone method to make the determination. |
| | | * If you're really going to attempt pattern matching on a DN, then I'd |
| | | * suggest trying a regular expression against the normalized DN rather |
| | | * than a filter. |
| | | */ |
| | | /** |
| | | * This method tries to match a pattern against a DN. It builds an entry |
| | | * with a target attribute containing the pattern and then matches against |
| | | * it. |
| | | * @param dn The DN to try an match. |
| | | * @return True if the pattern matches. |
| | | */ |
| | | public boolean matchesPattern(DN dn) { |
| | | boolean ret; |
| | | String targetDN=dn.toNormalizedString(); |
| | | LinkedHashSet<AttributeValue> values = |
| | | new LinkedHashSet<AttributeValue>(); |
| | | values.add(new AttributeValue(targetType, targetDN)); |
| | | Attribute attr = new Attribute(targetType, "target", values); |
| | | Entry e = new Entry(DN.nullDN(), null, null, null); |
| | | e.addAttribute(attr,new ArrayList<AttributeValue>()); |
| | | try { |
| | | ret=filter.matchesEntry(e); |
| | | } catch (DirectoryException ex) { |
| | | //TODO information message? |
| | | return false; |
| | | } |
| | | 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; |
| | | |
| | | import static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import java.util.HashSet; |
| | | import java.util.regex.Pattern; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.types.AttributeType; |
| | | |
| | | /** |
| | | * A class representing an ACI's targetattr keyword. |
| | | */ |
| | | public class TargetAttr { |
| | | private EnumTargetOperator operator = EnumTargetOperator.EQUALITY; |
| | | private boolean allAttributes = false ; |
| | | /* |
| | | * HashSet of the attribute types parsed by the constructor. |
| | | */ |
| | | private HashSet<AttributeType> attributes = new HashSet<AttributeType>(); |
| | | //private String[] attributes = new String[0]; |
| | | private static final String allAttrsRegex = "\\s*\\*\\s*"; |
| | | private static final String noAttrsRegex = "\\s*"; |
| | | private static final String separatorToken = "\\|\\|"; |
| | | private static final String attrListRegex = |
| | | "\\s*(\\w+)\\s*(" + separatorToken + "\\s*(\\w+)\\s*)*"; |
| | | |
| | | /** |
| | | * Constructor creating a class representing a targetattr keyword of an ACI. |
| | | * @param operator The operation enumeration of the targetattr |
| | | * expression (=, !=). |
| | | * @param attrString A string representing the attributes specified in |
| | | * the targetattr expression (ie, dn || cn). |
| | | * @throws AciException If the attrs string is invalid. |
| | | */ |
| | | private TargetAttr(EnumTargetOperator operator, String attrString) |
| | | throws AciException { |
| | | this.operator = operator; |
| | | if (attrString != null) { |
| | | if (Pattern.matches(allAttrsRegex, attrString) ){ |
| | | allAttributes = true ; |
| | | } else { |
| | | if (Pattern.matches(noAttrsRegex, attrString)){ |
| | | allAttributes = false; |
| | | } else { |
| | | if (Pattern.matches(attrListRegex, attrString)) { |
| | | // Remove the spaces in the attr string and |
| | | // split the list. |
| | | Pattern separatorPattern = |
| | | Pattern.compile(separatorToken); |
| | | attrString=attrString.replaceAll("\\s", ""); |
| | | String[] attributeArray= |
| | | separatorPattern.split(attrString); |
| | | //Add each element of array to attributes HashSet |
| | | //after converting it to AttributeType. |
| | | arrayToAttributeTypes(attributeArray); |
| | | } else { |
| | | int msgID = |
| | | MSGID_ACI_SYNTAX_INVALID_TARGETATTRKEYWORD_EXPRESSION; |
| | | String message = getMessage(msgID, operator); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Converts each element of an array of attribute type strings |
| | | * to attribute types and adds them to the attributes HashSet. |
| | | * @param attributeArray The array of attribute type strings. |
| | | */ |
| | | private void arrayToAttributeTypes(String[] attributeArray) { |
| | | for (int i=0, n=attributeArray.length; i < n; i++) { |
| | | String attribute=attributeArray[i].toLowerCase(); |
| | | AttributeType attributeType; |
| | | if((attributeType = |
| | | DirectoryServer.getAttributeType(attribute)) == null) |
| | | attributeType = |
| | | DirectoryServer.getDefaultAttributeType(attribute); |
| | | attributes.add(attributeType); |
| | | } |
| | | } |
| | | /** |
| | | * Returns the operator enumeration of the targetattr expression. |
| | | * @return The operator enumeration. |
| | | */ |
| | | public EnumTargetOperator getOperator() { |
| | | return operator; |
| | | } |
| | | |
| | | /** |
| | | * This flag is set if the parsing code saw: |
| | | * targetattr="*" or targetattr != "*". |
| | | * @return True if all attributes was seen. |
| | | */ |
| | | public boolean isAllAttributes() { |
| | | return allAttributes; |
| | | } |
| | | |
| | | /** |
| | | * Return array holding each attribute type to be evaluated |
| | | * in the expression. |
| | | * @return Array holding each attribute types. |
| | | */ |
| | | public HashSet<AttributeType> getAttributes() { |
| | | return attributes; |
| | | } |
| | | |
| | | /** |
| | | * Decodes an targetattr expression string into a targetattr class suitable |
| | | * for evaluation. |
| | | * @param operator The operator enumeration of the expression. |
| | | * @param expr The expression string to be decoded. |
| | | * @return A TargetAttr suitable to evaluate this ACI's targetattrs. |
| | | * @throws AciException If the expression string is invalid. |
| | | */ |
| | | public static TargetAttr decode(EnumTargetOperator operator, String expr) |
| | | throws AciException { |
| | | return new TargetAttr(operator, expr); |
| | | } |
| | | |
| | | /** |
| | | * Perform two checks to see if a specified attribute type is applicable. |
| | | * First, check the targetAttr's isAllAttributes() boolean. The |
| | | * isAllAttributes boolean is set true when the string: |
| | | * |
| | | * 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. |
| | | * |
| | | * If the isAllAttributes boolean is false, then the TargeAttr's |
| | | * 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. |
| | | * |
| | | * @param a The attribute type to evaluate. |
| | | * @param targetAttr The ACI's TargetAttr class to evaluate against. |
| | | * @return The boolean result of the above tests and application |
| | | * TargetAttr's operator value applied to the test result. |
| | | */ |
| | | public static boolean isApplicable(AttributeType a, |
| | | TargetAttr targetAttr) { |
| | | boolean ret; |
| | | if(targetAttr.isAllAttributes()) { |
| | | ret = |
| | | !targetAttr.getOperator().equals(EnumTargetOperator.NOT_EQUALITY); |
| | | } else { |
| | | ret=false; |
| | | HashSet<AttributeType> attributes=targetAttr.getAttributes(); |
| | | if(attributes.contains(a)) |
| | | ret=true; |
| | | 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.authorization.dseecompat; |
| | | |
| | | import static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.SearchFilter; |
| | | |
| | | /** |
| | | * This class represents a targetfilter keyword of an aci. |
| | | * |
| | | */ |
| | | public class TargetFilter { |
| | | private EnumTargetOperator op = EnumTargetOperator.EQUALITY; |
| | | private SearchFilter filter; |
| | | |
| | | /** |
| | | * Class representing a targetfilter keyword. |
| | | * @param op The operation of the targetfilter expression (=, !=) |
| | | * @param filter The filter itself. |
| | | */ |
| | | private TargetFilter(EnumTargetOperator op, SearchFilter filter) { |
| | | this.op=op; |
| | | this.filter=filter; |
| | | } |
| | | |
| | | /** |
| | | * Decode a aci's targetfilter string. |
| | | * @param op The operation enumeration of the expression. |
| | | * @param expr A string representing the target filter. |
| | | * @return A TargetFilter class suitable for using in a match. |
| | | * @throws AciException If the expression string is invalid. |
| | | */ |
| | | public static TargetFilter decode(EnumTargetOperator op, String expr) |
| | | throws AciException { |
| | | SearchFilter filter; |
| | | try { |
| | | filter = SearchFilter.createFilterFromString(expr); |
| | | } catch (DirectoryException ex) { |
| | | int msgID = |
| | | MSGID_ACI_SYNTAX_INVALID_TARGETFILTERKEYWORD_EXPRESSION; |
| | | String message = getMessage(msgID, expr); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | return new TargetFilter(op, filter); |
| | | } |
| | | |
| | | /** |
| | | * Checks if a targetfilter matches an evaluation context. |
| | | * @param matchCtx The evaluation context to use in the matching. |
| | | * @return True if the target filter matched the context. |
| | | */ |
| | | public boolean isApplicable(AciTargetMatchContext matchCtx) { |
| | | boolean ret; |
| | | ret=matchesFilter(matchCtx.getResourceEntry()); |
| | | if(op.equals(EnumTargetOperator.NOT_EQUALITY)) |
| | | ret = !ret; |
| | | return ret; |
| | | } |
| | | |
| | | /** |
| | | * Checks the filter against an entry taken from the match context. |
| | | * @param e The entry from the evaluation context above. |
| | | * @return True if the filter matches the entry. |
| | | */ |
| | | private boolean matchesFilter(Entry e) { |
| | | boolean ret; |
| | | try { |
| | | ret=filter.matchesEntry(e); |
| | | } catch (DirectoryException ex) { |
| | | //TODO information message? |
| | | return false; |
| | | } |
| | | 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; |
| | | |
| | | import static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import org.opends.server.util.TimeThread; |
| | | import java.util.regex.Pattern; |
| | | |
| | | /** |
| | | * This class represents the timeofday keyword in a bind rule. |
| | | */ |
| | | public class TimeOfDay implements KeywordBindRule { |
| | | private static final String timeofdayRegex = "[0-2]\\d[0-5]\\d"; |
| | | private EnumBindRuleType type=null; |
| | | private int timeRef; |
| | | |
| | | /** |
| | | * Constructor to create a timeofday keyword class. |
| | | * @param timeVal The time value to check for (0-2359). |
| | | * @param type An enumeration of the type of the expression. |
| | | */ |
| | | private TimeOfDay(int timeVal, EnumBindRuleType type) { |
| | | this.timeRef=timeVal; |
| | | this.type=type; |
| | | } |
| | | |
| | | /** |
| | | * Decodes a string representation of a timeofday bind rule expression. |
| | | * @param expr A string representation of the expression. |
| | | * @param type An enumeration of the type of the expression. |
| | | * @return A TimeOfDay class representing the expression. |
| | | * @throws AciException If the expression is invalid. |
| | | */ |
| | | public static TimeOfDay decode(String expr, EnumBindRuleType type) |
| | | throws AciException { |
| | | if (!Pattern.matches(timeofdayRegex, expr)) |
| | | { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_TIMEOFDAY; |
| | | String message = getMessage(msgID,expr); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | int valueAsInt = Integer.parseInt(expr); |
| | | if ((valueAsInt < 0) || (valueAsInt > 2359)) |
| | | { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_TIMEOFDAY_RANGE; |
| | | String message = getMessage(msgID,expr); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | |
| | | return new TimeOfDay(valueAsInt, type); |
| | | } |
| | | |
| | | /** |
| | | * Evaluates the timeofday bind rule using the evaluation context |
| | | * passed into the method. |
| | | * @param evalCtx The evaluation context to use for the evaluation. |
| | | * @return An enumeration result representing the result of the |
| | | * evaluation. |
| | | */ |
| | | public EnumEvalResult evaluate(AciEvalContext evalCtx) { |
| | | EnumEvalResult matched=EnumEvalResult.FALSE; |
| | | |
| | | int currentTime=TimeThread.getHourAndMinute(); |
| | | //check the type |
| | | switch (type) { |
| | | case LESS_OR_EQUAL_BINDRULE_TYPE: |
| | | if (currentTime <= timeRef) |
| | | { |
| | | matched=EnumEvalResult.TRUE; |
| | | } |
| | | break; |
| | | |
| | | case LESS_BINDRULE_TYPE: |
| | | if (currentTime < timeRef) |
| | | { |
| | | matched=EnumEvalResult.TRUE; |
| | | } |
| | | break; |
| | | |
| | | case GREATER_OR_EQUAL_BINDRULE_TYPE: |
| | | if (currentTime >= timeRef) |
| | | { |
| | | matched=EnumEvalResult.TRUE; |
| | | } |
| | | break; |
| | | |
| | | case GREATER_BINDRULE_TYPE: |
| | | if (currentTime > timeRef) |
| | | { |
| | | matched=EnumEvalResult.TRUE; |
| | | } |
| | | } |
| | | return matched.getRet(type, false); |
| | | } |
| | | } |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.protocols.internal.InternalClientConnection; |
| | | import org.opends.server.protocols.internal.InternalSearchOperation; |
| | | import org.opends.server.types.*; |
| | | /* |
| | | * TODO Evaluate making this class more efficient. |
| | | * |
| | | * This class isn't as efficient as it could be. For example, the evalVAL() |
| | | * method should be able to use cached versions of the attribute type and |
| | | * filter. The evalURL() and evalDN() methods should also be able to use a |
| | | * cached version of the attribute type. |
| | | */ |
| | | /** |
| | | * This class implements the userattr bind rule keyword. |
| | | */ |
| | | public class UserAttr implements KeywordBindRule { |
| | | /** |
| | | * This enumeration is the various types the userattr can have after |
| | | * the "#" token. |
| | | */ |
| | | enum UserAttrType { |
| | | USERDN, GROUPDN, ROLEDN, URL, VALUE |
| | | } |
| | | private static String f="objectclass=*"; |
| | | private String attrStr=null; |
| | | private String attrVal=null; |
| | | private UserAttrType userAttrType=null; |
| | | private EnumBindRuleType type=null; |
| | | private ParentInheritance parentInheritance=null; |
| | | |
| | | /** |
| | | * Create an non-USERDN/GROUPDN instance of the userattr keyword class. |
| | | * @param attrStr The attribute name in string form. Kept in string form |
| | | * until processing. |
| | | * @param attrVal The attribute value in string form -- used in the USERDN |
| | | * evaluation for the parent hierarchy expression. |
| | | * @param userAttrType The userattr type of the rule |
| | | * "USERDN, GROUPDN, ...". |
| | | * @param type The bind rule type "=, !=". |
| | | */ |
| | | private UserAttr(String attrStr, String attrVal, UserAttrType userAttrType, |
| | | EnumBindRuleType type) { |
| | | this.attrStr=attrStr; |
| | | this.attrVal=attrVal; |
| | | this.userAttrType=userAttrType; |
| | | this.type=type; |
| | | } |
| | | |
| | | /** |
| | | * Create an USERDN or GROUPDN instance of the userattr keyword class. |
| | | * @param userAttrType The userattr type of the rule (USERDN or GROUPDN) |
| | | * only. |
| | | * @param type The bind rule type "=, !=". |
| | | * @param parentInheritance The parent inheritance class to use for parent |
| | | * inheritance checks if any. |
| | | */ |
| | | private UserAttr(UserAttrType userAttrType, EnumBindRuleType type, |
| | | ParentInheritance parentInheritance) { |
| | | this.userAttrType=userAttrType; |
| | | this.type=type; |
| | | this.parentInheritance=parentInheritance; |
| | | } |
| | | /** |
| | | * Decode an string containing the userattr bind rule expression. |
| | | * @param expression The expression string. |
| | | * @param type The bind rule type. |
| | | * @return A class suitable for evaluating a userattr bind rule. |
| | | * @throws AciException If the string contains an invalid expression. |
| | | */ |
| | | public static KeywordBindRule decode(String expression, |
| | | EnumBindRuleType type) |
| | | throws AciException { |
| | | String[] vals=expression.split("#"); |
| | | if(vals.length != 2) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_USERATTR_EXPRESSION; |
| | | String message = getMessage(msgID, expression); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | UserAttrType userAttrType=getType(vals[1]); |
| | | switch (userAttrType) { |
| | | case GROUPDN: |
| | | case USERDN: { |
| | | ParentInheritance parentInheritance = |
| | | new ParentInheritance(vals[0], false); |
| | | return new UserAttr (userAttrType, type, parentInheritance); |
| | | } |
| | | case ROLEDN: { |
| | | //Even though parent inheritance is invalid for the ROLEDN |
| | | //keyword, we are going to up a simple parent inheritance |
| | | //class so that most of the evaluate methods in this class |
| | | //can be re-used. The true boolean means to skip parsing, |
| | | //except for a quick validation parse. |
| | | ParentInheritance parentInheritance = |
| | | new ParentInheritance(vals[0], true); |
| | | return new UserAttr(userAttrType, type, parentInheritance); |
| | | } |
| | | } |
| | | return new UserAttr(vals[0], vals[1], userAttrType, type); |
| | | } |
| | | |
| | | /** |
| | | * Evaluate the expression using an evaluation context. |
| | | * @param evalCtx The evaluation context to use in the evaluation of the |
| | | * userattr expression. |
| | | * @return An enumeration containing the result of the evaluation. |
| | | */ |
| | | public EnumEvalResult evaluate(AciEvalContext evalCtx) { |
| | | EnumEvalResult matched; |
| | | boolean undefined=false; |
| | | |
| | | switch(userAttrType) { |
| | | case ROLEDN: |
| | | case GROUPDN: |
| | | case USERDN: { |
| | | matched=evalDNKeywords(evalCtx); |
| | | break; |
| | | } |
| | | case URL: { |
| | | matched=evalURL(evalCtx); |
| | | break; |
| | | } |
| | | default: |
| | | matched=evalVAL(evalCtx); |
| | | } |
| | | if(matched == EnumEvalResult.ERR) |
| | | undefined=true; |
| | | return matched.getRet(type, undefined); |
| | | } |
| | | |
| | | /** Evaluate a VALUE userattr type. Look in client entry for an |
| | | * attribute value and in the resource entry for the same |
| | | * value. If both entries have the same value than return true. |
| | | * @param evalCtx The evaluation context to use. |
| | | * @return An enumeration containing the result of the |
| | | * evaluation. |
| | | */ |
| | | private EnumEvalResult evalVAL(AciEvalContext evalCtx) { |
| | | EnumEvalResult matched= EnumEvalResult.FALSE; |
| | | boolean undefined=false; |
| | | AttributeType attrType; |
| | | if((attrType = DirectoryServer.getAttributeType(attrStr)) == null) |
| | | attrType = DirectoryServer.getDefaultAttributeType(attrStr); |
| | | try { |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | InternalSearchOperation op = |
| | | conn.processSearch(evalCtx.getClientDN(), |
| | | SearchScope.BASE_OBJECT, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString(f), null); |
| | | LinkedList<SearchResultEntry> result = op.getSearchEntries(); |
| | | if (!result.isEmpty()) { |
| | | AttributeValue val=new AttributeValue(attrType, attrVal); |
| | | SearchResultEntry resultEntry = result.getFirst(); |
| | | if(resultEntry.hasValue(attrType, null, val)) { |
| | | Entry e=evalCtx.getResourceEntry(); |
| | | if(e.hasValue(attrType, null, val)) |
| | | matched=EnumEvalResult.TRUE; |
| | | } |
| | | } |
| | | } catch (DirectoryException ex) { |
| | | undefined = true; |
| | | matched = EnumEvalResult.ERR; |
| | | } |
| | | return matched.getRet(type, undefined); |
| | | } |
| | | |
| | | /** |
| | | * Parses the substring after the '#' character to determine the userattr |
| | | * type. |
| | | * @param expr The string with the substring. |
| | | * @return An enumeration containing the type. |
| | | * @throws AciException If the substring contains an invalid type (roledn |
| | | * or groupdn). |
| | | */ |
| | | private static UserAttrType getType(String expr) throws AciException { |
| | | UserAttrType userAttrType; |
| | | if(expr.equalsIgnoreCase("userdn")) |
| | | userAttrType=UserAttrType.USERDN; |
| | | else if(expr.equalsIgnoreCase("groupdn")) { |
| | | userAttrType=UserAttrType.GROUPDN; |
| | | /* |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_USERATTR_KEYWORD; |
| | | String message = getMessage(msgID, "The groupdn userattr" + |
| | | "keyword is not supported."); |
| | | throw new AciException(msgID, message); |
| | | */ |
| | | } else if(expr.equalsIgnoreCase("roledn")) { |
| | | userAttrType=UserAttrType.ROLEDN; |
| | | /* |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_USERATTR_KEYWORD; |
| | | String message = getMessage(msgID, "The roledn userattr" + |
| | | "keyword is not supported."); |
| | | throw new AciException(msgID, message); |
| | | */ |
| | | } else if(expr.equalsIgnoreCase("ldapurl")) |
| | | userAttrType=UserAttrType.URL; |
| | | else |
| | | userAttrType=UserAttrType.VALUE; |
| | | return userAttrType; |
| | | } |
| | | |
| | | /** |
| | | * Evaluate an URL userattr type. Look into the resource entry for the |
| | | * specified attribute and values. Assume it is an URL. Decode it an try |
| | | * and match it against the client entry attribute. |
| | | * @param evalCtx The evaluation context to evaluate with. |
| | | * @return An enumeration containing a result of the URL evaluation. |
| | | */ |
| | | private EnumEvalResult evalURL(AciEvalContext evalCtx) { |
| | | EnumEvalResult matched= EnumEvalResult.FALSE; |
| | | boolean undefined=false; |
| | | AttributeType attrType; |
| | | if((attrType = DirectoryServer.getAttributeType(attrStr)) == null) |
| | | attrType = DirectoryServer.getDefaultAttributeType(attrStr); |
| | | List<Attribute> attrs=evalCtx.getResourceEntry().getAttribute(attrType); |
| | | if(!attrs.isEmpty()) { |
| | | for(Attribute a : attrs) { |
| | | LinkedHashSet<AttributeValue> vals=a.getValues(); |
| | | for(AttributeValue v : vals) { |
| | | String urlStr=v.getStringValue(); |
| | | LDAPURL url; |
| | | try { |
| | | url=LDAPURL.decode(urlStr, true); |
| | | } catch (DirectoryException e) { |
| | | break; |
| | | } |
| | | matched=UserDN.evalURL(evalCtx, url); |
| | | if(matched != EnumEvalResult.FALSE) |
| | | break; |
| | | } |
| | | if(matched == EnumEvalResult.TRUE) |
| | | break; |
| | | if(matched == EnumEvalResult.ERR) { |
| | | undefined=true; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | return matched.getRet(type, undefined); |
| | | } |
| | | |
| | | /** |
| | | * Evaluate the DN type userattr keywords. These are roledn, userdn and |
| | | * groupdn. The processing is the same for all three, although roledn is |
| | | * a slightly different. For the roledn userattr keyword, a very simple |
| | | * parent inheritance class was created. The rest of the processing is the |
| | | * same for all three keywords. |
| | | * |
| | | * @param evalCtx The evaluation context to evaluate with. |
| | | * @return An enumeration containing a result of the USERDN evaluation. |
| | | */ |
| | | private EnumEvalResult evalDNKeywords(AciEvalContext evalCtx) { |
| | | EnumEvalResult matched= EnumEvalResult.FALSE; |
| | | boolean undefined=false, stop=false; |
| | | int numLevels=parentInheritance.getNumLevels(); |
| | | int[] levels=parentInheritance.getLevels(); |
| | | AttributeType attrType=parentInheritance.getAttributeType(); |
| | | for(int i=0;((i < numLevels) && !stop); i++ ) { |
| | | //The ROLEDN keyword will always enter this statement. The others |
| | | //might. For the add operation, the resource itself (level 0) |
| | | //must never be allowed to give access. |
| | | if(levels[i] == 0) { |
| | | if(evalCtx.isAddOperation()) { |
| | | undefined=true; |
| | | } else if (evalCtx.getResourceEntry().hasAttribute(attrType)) { |
| | | matched = |
| | | evalEntryAttr(evalCtx.getResourceEntry(), |
| | | evalCtx,attrType); |
| | | if(matched.equals(EnumEvalResult.TRUE)) |
| | | stop=true; |
| | | } |
| | | } else { |
| | | try { |
| | | DN pDN= |
| | | getDNParentLevel(levels[i], evalCtx.getResourceDN()); |
| | | if(pDN == null) |
| | | continue; |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | InternalSearchOperation op = conn.processSearch(pDN, |
| | | SearchScope.BASE_OBJECT, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString(f), null); |
| | | LinkedList<SearchResultEntry> result = |
| | | op.getSearchEntries(); |
| | | if (!result.isEmpty()) { |
| | | Entry e = result.getFirst(); |
| | | if (e.hasAttribute(attrType)) { |
| | | matched = evalEntryAttr(e, evalCtx, attrType); |
| | | if(matched.equals(EnumEvalResult.TRUE)) |
| | | stop=true; |
| | | } |
| | | } |
| | | } catch (DirectoryException ex) { |
| | | undefined=true; |
| | | stop=true; |
| | | matched=EnumEvalResult.ERR; |
| | | } |
| | | } |
| | | } |
| | | return matched.getRet(type, undefined); |
| | | } |
| | | |
| | | /** |
| | | * This method returns a parent DN based on the level. Not very |
| | | * sophisticated but it works. |
| | | * @param l The level. |
| | | * @param dn The DN to get the parent of. |
| | | * @return Parent DN based on the level or null if the level is greater |
| | | * than the rdn count. |
| | | */ |
| | | private DN getDNParentLevel(int l, DN dn) { |
| | | int rdns=dn.getNumComponents(); |
| | | if(l > rdns) |
| | | return null; |
| | | DN theDN=dn; |
| | | for(int i=0; i < l;i++) { |
| | | theDN=theDN.getParent(); |
| | | } |
| | | return theDN; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * This method evaluates the user attribute type and calls the correct |
| | | * evalaution method. The three user attribute types that can be selected |
| | | * are ROLEDN, USERDN or GROUPDN. |
| | | * @param e The entry to use in the evaluation. |
| | | * @param evalCtx The evaluation context to use in the evaluation. |
| | | * @param attributeType The attribute type to use in the evaluation. |
| | | * @return The result of the evaluation routine. |
| | | */ |
| | | private EnumEvalResult evalEntryAttr(Entry e, AciEvalContext evalCtx, |
| | | AttributeType attributeType) { |
| | | EnumEvalResult result=EnumEvalResult.FALSE; |
| | | switch (userAttrType) { |
| | | case USERDN: { |
| | | result=UserDN.evaluate(e, evalCtx.getClientDN(), |
| | | attributeType); |
| | | break; |
| | | } |
| | | case ROLEDN: |
| | | result=RoleDN.evaluate(e, evalCtx, attributeType); |
| | | break; |
| | | case GROUPDN: { |
| | | result=GroupDN.evaluate(e, evalCtx, attributeType); |
| | | break; |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | } |
| 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 static org.opends.server.authorization.dseecompat.AciMessages.*; |
| | | import static org.opends.server.messages.MessageHandler.getMessage; |
| | | |
| | | import java.util.*; |
| | | import org.opends.server.types.*; |
| | | import org.opends.server.core.DirectoryServer; |
| | | |
| | | /** |
| | | * This class represents the userdn keyword in a bind rule. |
| | | */ |
| | | public class UserDN implements KeywordBindRule { |
| | | /* |
| | | * A dummy URL for invalid URLs such as: all, parent, anyone, self. |
| | | */ |
| | | private static String urlStr="ldap:///"; |
| | | |
| | | /** |
| | | * This list holds a list of objects representing a EnumUserDNType |
| | | * URL mapping. |
| | | */ |
| | | List<UserDNTypeURL> urlList=null; |
| | | private EnumBindRuleType type=null; |
| | | private AttributeType userDNAttrType; |
| | | /** |
| | | * Constructor that creates the userdn class. It also sets up an attribute |
| | | * type ("userdn") needed for wild-card matching. |
| | | * @param type The type of operation. |
| | | * @param urlList A list of enumerations containing the URL type and URL |
| | | * object that can be retrieved at evaluation time. |
| | | */ |
| | | private UserDN(EnumBindRuleType type, List<UserDNTypeURL> urlList) { |
| | | this.type=type; |
| | | this.urlList=urlList; |
| | | userDNAttrType = DirectoryServer.getAttributeType("userdn"); |
| | | if (userDNAttrType == null) |
| | | userDNAttrType = DirectoryServer.getDefaultAttributeType("userdn"); |
| | | } |
| | | |
| | | /** |
| | | * Decodes an expression string representing a userdn bind rule. |
| | | * @param expression The string representation of the userdn bind rule |
| | | * expression. |
| | | * @param type An enumeration of the type of the bind rule. |
| | | * @return A KeywordBindRule class that represents the bind rule. |
| | | * @throws AciException If the expression failed to LDAP URL decode. |
| | | */ |
| | | public static KeywordBindRule decode(String expression, |
| | | EnumBindRuleType type) throws AciException { |
| | | |
| | | String[] vals=expression.split("[|][|]"); |
| | | List<UserDNTypeURL> urlList = new LinkedList<UserDNTypeURL>(); |
| | | for(int i=0, m=vals.length; i < m; i++) |
| | | { |
| | | StringBuilder value = new StringBuilder(vals[i].trim()); |
| | | /* |
| | | * TODO Evaluate using a wild-card in the dn portion of LDAP url. |
| | | * The current implementation (DS6) does not treat a "*" |
| | | * as a wild-card. |
| | | * |
| | | * Is it allowed to have a full LDAP URL (i.e., including a base, |
| | | * scope, and filter) in which the base DN contains asterisks to |
| | | * make it a wildcard? If so, then I don't think that the current |
| | | * implementation handles that correctly. It will probably fail |
| | | * when attempting to create the LDAP URL because the base DN isn't a |
| | | * valid DN. |
| | | */ |
| | | EnumUserDNType userDNType = UserDN.getType(value); |
| | | LDAPURL url; |
| | | try { |
| | | url=LDAPURL.decode(value.toString(), true); |
| | | } catch (DirectoryException de) { |
| | | int msgID = MSGID_ACI_SYNTAX_INVALID_USERDN_URL; |
| | | String message = getMessage(msgID, de.getErrorMessage()); |
| | | throw new AciException(msgID, message); |
| | | } |
| | | UserDNTypeURL dnTypeURL=new UserDNTypeURL(userDNType, url); |
| | | urlList.add(dnTypeURL); |
| | | } |
| | | return new UserDN(type, urlList); |
| | | } |
| | | |
| | | /** |
| | | * This method determines the type of the DN (suffix in URL terms) |
| | | * part of a URL, by examining the full URL itself for known strings |
| | | * such as (corresponding type shown in parenthesis) |
| | | * |
| | | * "ldap:///anyone" (EnumUserDNType.ANYONE) |
| | | * "ldap:///parent" (EnumUserDNType.PARENT) |
| | | * "ldap:///all" (EnumUserDNType.ALL) |
| | | * "ldap:///self" (EnumUserDNType.SELF) |
| | | * |
| | | * If one of the four above are found, the URL is replaced with a dummy |
| | | * pattern "ldap:///". This is done because the above four are invalid |
| | | * URLs; but the syntax is valid for an userdn keyword expression. The |
| | | * dummy URLs are never used. |
| | | * |
| | | * If none of the above are found, it determine if the URL DN is a |
| | | * substring pattern, such as: |
| | | * |
| | | * "ldap:///uid=*, dc=example, dc=com" (EnumUserDNType.PATTERN) |
| | | * |
| | | * If none of the above are determined, it checks if the URL |
| | | * is a complete URL with scope and filter defined: |
| | | * |
| | | * "ldap:///uid=test,dc=example,dc=com??sub?(cn=j*)" (EnumUserDNType.URL) |
| | | * |
| | | * If none of these those types can be identified, it defaults to |
| | | * EnumUserDNType.DN. |
| | | * |
| | | * @param bldr A string representation of the URL that can be modified. |
| | | * @return The user DN type of the URL. |
| | | */ |
| | | private static EnumUserDNType getType(StringBuilder bldr) { |
| | | EnumUserDNType type; |
| | | String str=bldr.toString(); |
| | | |
| | | if(str.indexOf("?") != -1) { |
| | | type = EnumUserDNType.URL; |
| | | } else if(str.equalsIgnoreCase("ldap:///self")) { |
| | | type = EnumUserDNType.SELF; |
| | | bldr.replace(0, bldr.length(), urlStr); |
| | | } else if(str.equalsIgnoreCase("ldap:///anyone")) { |
| | | type = EnumUserDNType.ANYONE; |
| | | bldr.replace(0, bldr.length(), urlStr); |
| | | } else if(str.equalsIgnoreCase("ldap:///parent")) { |
| | | type = EnumUserDNType.PARENT; |
| | | bldr.replace(0, bldr.length(), urlStr); |
| | | } else if(str.equalsIgnoreCase("ldap:///all")) { |
| | | type = EnumUserDNType.ALL; |
| | | bldr.replace(0, bldr.length(), urlStr); |
| | | } else if(str.indexOf("*") != -1) { |
| | | type = EnumUserDNType.DNPATTERN; |
| | | } else { |
| | | type = EnumUserDNType.DN; |
| | | } |
| | | return type; |
| | | } |
| | | |
| | | /** |
| | | * Performs the evaluation of a userdn bind rule based on the |
| | | * evaluation context passed to it. The evaluation stops when there |
| | | * are no more UserDNTypeURLs to evaluate or if an UserDNTypeURL |
| | | * evaluates to true. |
| | | * @param evalCtx The evaluation context to evaluate with. |
| | | * @return An evaluation result enumeration containing the result |
| | | * of the evaluation. |
| | | */ |
| | | public EnumEvalResult evaluate(AciEvalContext evalCtx) { |
| | | EnumEvalResult matched = EnumEvalResult.FALSE; |
| | | boolean undefined=false; |
| | | |
| | | boolean isAnonUser=evalCtx.isAnonymousUser(); |
| | | Iterator<UserDNTypeURL> it=urlList.iterator(); |
| | | for(; it.hasNext() && matched != EnumEvalResult.TRUE && |
| | | matched != EnumEvalResult.ERR;) { |
| | | UserDNTypeURL dnTypeURL=it.next(); |
| | | //Handle anonymous checks here |
| | | if(isAnonUser) { |
| | | if(dnTypeURL.getUserDNType() == EnumUserDNType.ANYONE) |
| | | matched = EnumEvalResult.TRUE; |
| | | } else |
| | | matched=evalNonAnonymous(evalCtx, dnTypeURL); |
| | | } |
| | | return matched.getRet(type, undefined); |
| | | } |
| | | |
| | | /** |
| | | * Performs an evaluation of a single UserDNTypeURL of a userdn bind |
| | | * rule using the evaluation context provided. This method is called |
| | | * for the non-anonymous user case. |
| | | * @param evalCtx The evaluation context to evaluate with. |
| | | * @param dnTypeURL The URL dn type mapping to evaluate. |
| | | * @return An evaluation result enumeration containing the result |
| | | * of the evaluation. |
| | | */ |
| | | private EnumEvalResult evalNonAnonymous(AciEvalContext evalCtx, |
| | | UserDNTypeURL dnTypeURL) { |
| | | DN clientDN=evalCtx.getClientDN(); |
| | | DN resDN=evalCtx.getResourceDN(); |
| | | EnumEvalResult matched = EnumEvalResult.FALSE; |
| | | EnumUserDNType type=dnTypeURL.getUserDNType(); |
| | | LDAPURL url=dnTypeURL.getURL(); |
| | | switch (type) { |
| | | case URL: |
| | | { |
| | | matched = evalURL(evalCtx, url); |
| | | break; |
| | | } |
| | | case ANYONE: |
| | | { |
| | | matched = EnumEvalResult.TRUE; |
| | | break; |
| | | } |
| | | case SELF: |
| | | { |
| | | if (clientDN.equals(resDN)) matched = EnumEvalResult.TRUE; |
| | | break; |
| | | } |
| | | case PARENT: |
| | | { |
| | | DN parentDN = resDN.getParent(); |
| | | if ((parentDN != null) && |
| | | (parentDN.equals(clientDN))) |
| | | matched = EnumEvalResult.TRUE; |
| | | break; |
| | | } |
| | | case ALL: |
| | | { |
| | | matched = EnumEvalResult.TRUE; |
| | | break; |
| | | } |
| | | case DNPATTERN: |
| | | { |
| | | matched = evalDNPattern(evalCtx, url); |
| | | break; |
| | | } |
| | | case DN: |
| | | { |
| | | try |
| | | { |
| | | DN dn = url.getBaseDN(); |
| | | if (clientDN.equals(dn)) |
| | | matched = EnumEvalResult.TRUE; |
| | | } catch (DirectoryException ex) { |
| | | //TODO add message |
| | | } |
| | | } |
| | | } |
| | | return matched; |
| | | } |
| | | |
| | | /* |
| | | * TODO Evaluate making this more efficient. |
| | | * |
| | | * The evalDNPattern() method looks like it suffers from the |
| | | * same problem as the matchesPattern() method in the Target |
| | | * class. Creating a dummy entry and attempting to do substring |
| | | * matching on a DN is a pretty expensive and error-prone approach. |
| | | * Using a regular expression would likely be much more efficient and |
| | | * should be simpler. |
| | | */ |
| | | /** |
| | | * This method evaluates a DN pattern userdn expression. It creates a |
| | | * dummy entry and a substring filter and applies the filter to the |
| | | * entry. |
| | | * @param evalCtx The evaluation context to use. |
| | | * @param url The LDAP URL containing the pattern. |
| | | * @return An enumeration evaluation result. |
| | | */ |
| | | private EnumEvalResult evalDNPattern(AciEvalContext evalCtx, LDAPURL url) { |
| | | boolean rc; |
| | | EnumEvalResult ret=EnumEvalResult.TRUE; |
| | | String urlDN; |
| | | SearchFilter filter; |
| | | try { |
| | | urlDN=url.getBaseDN().toNormalizedString(); |
| | | String pattern="userdn="+urlDN; |
| | | filter=SearchFilter.createFilterFromString(pattern); |
| | | } catch (DirectoryException ex) { |
| | | return EnumEvalResult.FALSE; |
| | | } |
| | | LinkedHashSet<AttributeValue> vals = |
| | | new LinkedHashSet<AttributeValue>(); |
| | | String userDNStr=evalCtx.getClientDN().toNormalizedString(); |
| | | vals.add(new AttributeValue(userDNAttrType, userDNStr)); |
| | | Attribute attr = new Attribute(userDNAttrType, "userdn", vals); |
| | | Entry e = new Entry(DN.nullDN(), null, null, null); |
| | | e.addAttribute(attr,new ArrayList<AttributeValue>()); |
| | | try { |
| | | rc=filter.matchesEntry(e); |
| | | } catch (DirectoryException ex) { |
| | | return EnumEvalResult.FALSE; |
| | | } |
| | | if(!rc) |
| | | ret=EnumEvalResult.FALSE; |
| | | return ret; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * This method evaluates an URL userdn expression. Something like: |
| | | * ldap:///suffix??sub?(filter). It also searches for the client DN |
| | | * entry and saves it in the evaluation context for repeat evaluations |
| | | * that might come later in processing. |
| | | * |
| | | * @param evalCtx The evaluation context to use. |
| | | * @param url URL containing the URL to use in the evaluation. |
| | | * @return An enumeration of the evaluation result. |
| | | */ |
| | | public static EnumEvalResult evalURL(AciEvalContext evalCtx, LDAPURL url) { |
| | | EnumEvalResult ret=EnumEvalResult.FALSE; |
| | | DN urlDN; |
| | | SearchFilter filter; |
| | | try { |
| | | urlDN=url.getBaseDN(); |
| | | filter=url.getFilter(); |
| | | } catch (DirectoryException ex) { |
| | | return EnumEvalResult.FALSE; |
| | | } |
| | | SearchScope scope=url.getScope(); |
| | | if(scope == SearchScope.WHOLE_SUBTREE) { |
| | | if(!evalCtx.getClientDN().isDescendantOf(urlDN)) |
| | | return EnumEvalResult.FALSE; |
| | | } else if(scope == SearchScope.SINGLE_LEVEL) { |
| | | DN parent=evalCtx.getClientDN().getParent(); |
| | | if((parent != null) && !parent.equals(urlDN)) |
| | | return EnumEvalResult.FALSE; |
| | | } else { |
| | | if(!evalCtx.getClientDN().equals(urlDN)) |
| | | return EnumEvalResult.FALSE; |
| | | } |
| | | try { |
| | | if(filter.matchesEntry(evalCtx.getClientEntry())) |
| | | ret=EnumEvalResult.TRUE; |
| | | } catch (DirectoryException ex) { |
| | | return EnumEvalResult.FALSE; |
| | | } |
| | | return ret; |
| | | } |
| | | |
| | | /* |
| | | * TODO Evaluate making this method more efficient. |
| | | * |
| | | * The evalDNEntryAttr method isn't as efficient as it could be. It would |
| | | * probably be faster to to convert the clientDN to an AttributeValue and |
| | | * see if the entry has that value than to decode each value as a DN and |
| | | * see if it matches the clientDN. |
| | | */ |
| | | /** |
| | | * This method searches an entry for an attribute value that is |
| | | * treated as a DN. That DN is then compared against the client |
| | | * DN. |
| | | * @param e The entry to get the attribute type from. |
| | | * @param clientDN The client authorization DN to check for. |
| | | * @param attrType The attribute type from the bind rule. |
| | | * @return An enumeration with the result. |
| | | */ |
| | | public static EnumEvalResult evaluate(Entry e, DN clientDN, |
| | | AttributeType attrType) { |
| | | EnumEvalResult matched= EnumEvalResult.FALSE; |
| | | List<Attribute> attrs = e.getAttribute(attrType); |
| | | LinkedHashSet<AttributeValue> vals = attrs.get(0).getValues(); |
| | | for(AttributeValue v : vals) { |
| | | try { |
| | | DN dn=DN.decode(v.getStringValue()); |
| | | if(dn.equals(clientDN)) { |
| | | matched=EnumEvalResult.TRUE; |
| | | break; |
| | | } |
| | | } catch (DirectoryException ex) { |
| | | break; |
| | | } |
| | | } |
| | | return matched; |
| | | } |
| | | } |
| 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.LDAPURL; |
| | | |
| | | /** |
| | | * The UserDNTypeURL class contains the EnumUserDNType and the URL value, |
| | | * of a "userdn" URL decoded by the UserDN.decode() method. |
| | | */ |
| | | public class UserDNTypeURL { |
| | | /** |
| | | * The DN type of the URL. |
| | | */ |
| | | private EnumUserDNType dnType; |
| | | /* |
| | | * The URL value. Maybe a dummy value for types such as ANYONE or SELF. |
| | | */ |
| | | private LDAPURL url; |
| | | |
| | | /** |
| | | * Create a class representing the "userdn" URL decoded by the |
| | | * UserDN.decode() method. |
| | | * @param dnType The type of the URL determined by examining the DN |
| | | * or suffix. |
| | | * @param url The URL itself from the ACI "userdn" string expression. |
| | | */ |
| | | UserDNTypeURL(EnumUserDNType dnType, LDAPURL url) { |
| | | this.url=url; |
| | | this.dnType=dnType; |
| | | } |
| | | |
| | | /** |
| | | * Returns the DN type. |
| | | * @return The DN type of the URL. |
| | | */ |
| | | public EnumUserDNType getUserDNType() { |
| | | return this.dnType; |
| | | } |
| | | |
| | | /** Returns the URL. |
| | | * @return The URL decoded by the UserDN.decode() method. |
| | | */ |
| | | public LDAPURL getURL() { |
| | | return this.url; |
| | | } |
| | | } |