001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2008 Sun Microsystems, Inc.
026 */
027
028 package org.opends.server.authorization.dseecompat;
029 import org.opends.messages.Message;
030
031 import static org.opends.messages.AccessControlMessages.*;
032 import static org.opends.server.authorization.dseecompat.Aci.*;
033 import java.util.HashSet;
034 import java.util.regex.Pattern;
035 import org.opends.server.core.DirectoryServer;
036 import org.opends.server.types.AttributeType;
037
038 /**
039 * A class representing an ACI's targetattr keyword.
040 */
041 public class TargetAttr {
042 /*
043 * Enumeration representing the targetattr operator.
044 */
045 private EnumTargetOperator operator = EnumTargetOperator.EQUALITY;
046
047 /*
048 * Flags that is set if all user attributes pattern seen "*".
049 */
050 private boolean allUserAttributes = false ;
051
052 /*
053 * Flags that is set if all operational attributes pattern seen "+".
054 */
055 private boolean allOpAttributes = false ;
056
057 /*
058 * HashSet of the attribute types parsed by the constructor.
059 */
060 private HashSet<AttributeType> attributes = new HashSet<AttributeType>();
061
062 /**
063 * HashSet of the operational attribute types parsed by the constructor.
064 */
065 private HashSet<AttributeType> opAttributes = new HashSet<AttributeType>();
066
067 /*
068 * Regular expression that matches one or more ATTR_NAME's separated by
069 * the "||" token.
070 */
071 private static final String attrListRegex = ZERO_OR_MORE_WHITESPACE +
072 ATTR_NAME + ZERO_OR_MORE_WHITESPACE + "(" +
073 LOGICAL_OR + ZERO_OR_MORE_WHITESPACE + ATTR_NAME +
074 ZERO_OR_MORE_WHITESPACE + ")*";
075
076 /**
077 * Constructor creating a class representing a targetattr keyword of an ACI.
078 * @param operator The operation enumeration of the targetattr
079 * expression (=, !=).
080 * @param attrString A string representing the attributes specified in
081 * the targetattr expression (ie, dn || +).
082 * @throws AciException If the attrs string is invalid.
083 */
084 private TargetAttr(EnumTargetOperator operator, String attrString)
085 throws AciException {
086 this.operator = operator;
087 if (attrString != null) {
088 if (Pattern.matches(ALL_USER_ATTRS_WILD_CARD, attrString) )
089 allUserAttributes = true ;
090 else if (Pattern.matches(ALL_OP_ATTRS_WILD_CARD, attrString) )
091 allOpAttributes = true ;
092 else {
093 if (Pattern.matches(ZERO_OR_MORE_WHITESPACE, attrString)){
094 allUserAttributes = false;
095 allOpAttributes=false;
096 } else {
097 if (Pattern.matches(attrListRegex, attrString)) {
098 // Remove the spaces in the attr string and
099 // split the list.
100 Pattern separatorPattern =
101 Pattern.compile(LOGICAL_OR);
102 attrString=
103 attrString.replaceAll(ZERO_OR_MORE_WHITESPACE, "");
104 String[] attributeArray=
105 separatorPattern.split(attrString);
106 //Add each element of array to appropriate HashSet
107 //after conversion to AttributeType.
108 arrayToAttributeTypes(attributeArray, attrString);
109 } else {
110 Message message =
111 WARN_ACI_SYNTAX_INVALID_TARGETATTRKEYWORD_EXPRESSION.
112 get(attrString);
113 throw new AciException(message);
114 }
115 }
116 }
117 }
118 }
119
120
121 /**
122 * Converts each element of an array of attribute strings
123 * to attribute types and adds them to either the user attributes HashSet or
124 * the operational attributes HashSet. Also, scan for the shorthand tokens
125 * "*" for all user attributes and "+" for all operational attributes.
126 *
127 * @param attributeArray The array of attribute type strings.
128 * @param attrStr String used in error message if an Aci Exception
129 * is thrown.
130 * @throws AciException If the one of the attribute checks fails.
131 */
132 private void arrayToAttributeTypes(String[] attributeArray, String attrStr)
133 throws AciException {
134 for (int i=0, n=attributeArray.length; i < n; i++) {
135 String attribute=attributeArray[i].toLowerCase();
136 if(attribute.equals("*")) {
137 if(!allUserAttributes)
138 allUserAttributes=true;
139 else {
140 Message message =
141 WARN_ACI_TARGETATTR_INVALID_ATTR_TOKEN.get(attrStr);
142 throw new AciException(message);
143 }
144 } else if(attribute.equals("+")) {
145 if(!allOpAttributes)
146 allOpAttributes=true;
147 else {
148 Message message =
149 WARN_ACI_TARGETATTR_INVALID_ATTR_TOKEN.get(attrStr);
150 throw new AciException(message);
151 }
152 } else {
153 AttributeType attributeType;
154 if((attributeType =
155 DirectoryServer.getAttributeType(attribute)) == null)
156 attributeType =
157 DirectoryServer.getDefaultAttributeType(attribute);
158 if(attributeType.isOperational())
159 opAttributes.add(attributeType);
160 else
161 attributes.add(attributeType);
162 }
163 }
164 }
165
166 /**
167 * Returns the operator enumeration of the targetattr expression.
168 * @return The operator enumeration.
169 */
170 public EnumTargetOperator getOperator() {
171 return operator;
172 }
173
174 /**
175 * This flag is set if the parsing code saw:
176 * targetattr="*" or targetattr != "*".
177 * @return True if all attributes was seen.
178 */
179 public boolean isAllUserAttributes() {
180 return allUserAttributes;
181 }
182
183
184 /**
185 * This flag is set if the parsing code saw:
186 * targetattr="+" or targetattr != "+".
187 * @return True if all attributes was seen.
188 */
189 public boolean isAllOpAttributes() {
190 return allOpAttributes;
191 }
192
193 /**
194 * Return array holding each attribute type to be evaluated
195 * in the expression.
196 * @return Array holding each attribute types.
197 */
198 public HashSet<AttributeType> getAttributes() {
199 return attributes;
200 }
201
202 /**
203 * Return array holding operational attribute types to be evaluated
204 * in the expression.
205 * @return Array holding attribute types.
206 */
207 public HashSet<AttributeType> getOpAttributes() {
208 return opAttributes;
209 }
210
211 /**
212 * Decodes an targetattr expression string into a targetattr class suitable
213 * for evaluation.
214 * @param operator The operator enumeration of the expression.
215 * @param expr The expression string to be decoded.
216 * @return A TargetAttr suitable to evaluate this ACI's targetattrs.
217 * @throws AciException If the expression string is invalid.
218 */
219 public static TargetAttr decode(EnumTargetOperator operator, String expr)
220 throws AciException {
221 return new TargetAttr(operator, expr);
222 }
223
224 /**
225 * Performs test to see if the specified is applicable to the specified
226 * TargetAttr. First a check if the TargetAttr parsing code saw an
227 * expression like:
228 *
229 * (targetattrs="+ || *), (targetattrs != "* || +)
230 *
231 * where both shorthand tokens where parsed. IF so then the attribute type
232 * matches automatically (or not matches if NOT_EQUALITY).
233 *
234 * If there isn't a match, then the method evalAttrType is called to further
235 * evaluate the attribute type and targetAttr combination.
236 *
237 *
238 * @param a The attribute type to evaluate.
239 * @param targetAttr The ACI's TargetAttr class to evaluate against.
240 * @return The boolean result of the above tests and application
241 * TargetAttr's operator value applied to the test result.
242 */
243
244 public static boolean isApplicable(AttributeType a,
245 TargetAttr targetAttr) {
246 boolean ret;
247 if(targetAttr.isAllUserAttributes() && targetAttr.isAllOpAttributes()) {
248 ret =
249 !targetAttr.getOperator().equals(EnumTargetOperator.NOT_EQUALITY);
250 } else
251 ret=evalAttrType(a, targetAttr);
252
253 return ret;
254 }
255
256 /**
257 * First check is to see if the attribute type is operational. If so then
258 * a match is true if the allOpAttributes boolean is true or if the
259 * attribute type is found in the operational attributes HashSet.
260 * Both results can be negated if the expression operator is NOT_EQUALITY).
261 *
262 * Second check is similar to above, except the user attributes boolean
263 * and HashSet is examined.
264 *
265 *
266 * @param a The attribute type to evaluate.
267 * @param targetAttr The targetAttr to apply to the attribute type.
268 * @return True if the attribute type is applicable to the targetAttr.
269 */
270 private static
271 boolean evalAttrType(AttributeType a, TargetAttr targetAttr) {
272 boolean ret=false;
273 if(a.isOperational()) {
274 if(targetAttr.isAllOpAttributes() ||
275 targetAttr.opAttributes.contains(a))
276 ret=true;
277 if(targetAttr.isAllOpAttributes() ||
278 !targetAttr.opAttributes.isEmpty()) {
279 if(targetAttr.getOperator().
280 equals(EnumTargetOperator.NOT_EQUALITY))
281 ret=!ret;
282 }
283 } else {
284 if(targetAttr.isAllUserAttributes() ||
285 targetAttr.attributes.contains(a))
286 ret=true;
287 if(targetAttr.isAllUserAttributes() ||
288 !targetAttr.attributes.isEmpty()) {
289 if(targetAttr.getOperator().
290 equals(EnumTargetOperator.NOT_EQUALITY))
291 ret=!ret;
292 }
293 }
294 return ret;
295 }
296 }