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 org.opends.server.types.AttributeType;
032 import org.opends.server.types.SearchFilter;
033 import org.opends.server.types.DirectoryException;
034 import org.opends.server.core.DirectoryServer;
035 import static org.opends.messages.AccessControlMessages.*;
036 import static org.opends.server.authorization.dseecompat.Aci.*;
037 import java.util.regex.Pattern;
038 import java.util.regex.Matcher;
039 import java.util.LinkedHashMap;
040
041 /**
042 * The TargAttrFilterList class represents an targattrfilters list. A
043 * targattrfilters list looks like:
044 *
045 * "Op=attr1:F1 [(&& attr2:F2)*]
046 */
047 public class TargAttrFilterList {
048
049 /*
050 * The mask coresponding to the operation of this list (add or del).
051 */
052 private int mask=0;
053
054 /*
055 * ListHashMap keyed by the attribute type and mapping to the corresponding
056 * search filter. LinkedHashMap is used so everything is in order.
057 */
058 private LinkedHashMap<AttributeType, SearchFilter> attrFilterList;
059
060 /*
061 * Regular expression group count.
062 */
063 private static int expectedGroupCount=2;
064
065 /*
066 * Regular expression attribute group position.
067 */
068 private static int attributePos=1;
069
070 /*
071 * Regular expression filter group position.
072 */
073 private static int filterPos=2;
074
075 /*
076 * Regular expression used to match a filter list including the strange
077 * "and" token used to join the multiple attribute type filter pairs.
078 */
079 private static final String filterListSeperator =
080 ZERO_OR_MORE_WHITESPACE + "&&" + ZERO_OR_MORE_WHITESPACE;
081
082 /*
083 * Regular expression used to match an attribute filter pair.
084 */
085 private static final String attributeFilter=
086 ATTR_NAME + ZERO_OR_MORE_WHITESPACE + ":{1}" +
087 ZERO_OR_MORE_WHITESPACE + "(\\({1}.*\\){1})";
088
089 /**
090 * Construct a class representing an targattrfilters filter list.
091 * @param mask The mask representing the operation.
092 * @param attrFilterList The list map containing the attribute type
093 * filter mappings.
094 */
095 public TargAttrFilterList(int mask,
096 LinkedHashMap<AttributeType, SearchFilter> attrFilterList) {
097 this.mask=mask;
098 this.attrFilterList=attrFilterList;
099 }
100
101 /**
102 * Decode an TargAttrFilterList from the specified expression string.
103 * @param mask The mask representing the operation.
104 * @param expression The expression string to decode.
105 * @return A TargAttrFilterList class representing the targattrfilters
106 * filter list.
107 * @throws AciException If the expression string contains errors.
108 */
109 public static TargAttrFilterList decode(int mask, String expression)
110 throws AciException {
111 LinkedHashMap<AttributeType, SearchFilter> attrFilterList =
112 new LinkedHashMap<AttributeType, SearchFilter>();
113 String[] subExpressions=expression.split(filterListSeperator, -1);
114 //Iterate over each sub-expression, parse and add them to the list
115 //if there are no errors.
116 for(String subs : subExpressions) {
117 Pattern pattern=Pattern.compile(attributeFilter);
118 Matcher matcher=pattern.matcher(subs);
119 //Match the attribute:filter pair part of the expression
120 if(!matcher.find() || matcher.groupCount() != expectedGroupCount) {
121 Message message =
122 WARN_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LIST_FORMAT.
123 get(expression);
124 throw new AciException(message);
125 }
126 String attributeName=matcher.group(attributePos).toLowerCase();
127 //Strip off any options, so it will match the filter option
128 //handling.
129 int semicolon = attributeName.indexOf(';');
130 if (semicolon != -1)
131 attributeName=attributeName.substring(0, semicolon);
132 String filterString=matcher.group(filterPos);
133 AttributeType attributeType;
134 if((attributeType =
135 DirectoryServer.getAttributeType(attributeName)) == null)
136 attributeType =
137 DirectoryServer.getDefaultAttributeType(attributeName);
138 SearchFilter filter;
139 //Check if it is a valid filter and add it to the list map if ok.
140 try {
141 filter = SearchFilter.createFilterFromString(filterString);
142 attrFilterList.put(attributeType, filter);
143 } catch (DirectoryException ex) {
144 Message er=ex.getMessageObject();
145 Message message =
146 WARN_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LISTS_FILTER.
147 get(filterString, er);
148 throw new AciException(message);
149 }
150 //Verify the filter components. This check assures that each
151 //attribute type in the filter matches the provided attribute
152 //type.
153 verifyFilterComponents(filter, attributeType);
154 }
155 return new TargAttrFilterList(mask, attrFilterList);
156 }
157
158 /**
159 * Verify the filter component attribute types by assuring that each
160 * attribute type in the filter matches the specified attribute type.
161 * @param filter The filter to verify.
162 * @param type The attribute type to use in the verification.
163 * @throws AciException If the filter contains an attribute type not
164 * specified.
165 */
166 private static void verifyFilterComponents(SearchFilter filter,
167 AttributeType type)
168 throws AciException {
169 switch (filter.getFilterType()) {
170 case AND:
171 case OR: {
172 for (SearchFilter f : filter.getFilterComponents()) {
173 verifyFilterComponents(f, type);
174 }
175 break;
176 }
177 case NOT: {
178 SearchFilter f = filter.getNotComponent();
179 verifyFilterComponents(f, type);
180 break;
181 }
182 default: {
183 AttributeType attrType=filter.getAttributeType();
184 if(!attrType.equals(type)) {
185 Message message =
186 WARN_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LISTS_ATTR_FILTER.
187 get(filter.toString());
188 throw new AciException(message);
189 }
190 }
191 }
192 }
193
194 /**
195 * Return the mask of this TargAttrFilterList.
196 * @return The mask value.
197 */
198 public int getMask() {
199 return this.mask;
200 }
201
202 /**
203 * Check if the mask value of this TargAttrFilterList class contains the
204 * specified mask value.
205 * @param mask The mask to check for.
206 * @return True if the mask matches the specified value.
207 */
208 public boolean hasMask(int mask) {
209 return (this.mask & mask) != 0;
210 }
211
212 /**
213 * Return the list map holding the attribute type to filter mappings.
214 * @return The list map.
215 */
216 public
217 LinkedHashMap<AttributeType, SearchFilter> getAttributeTypeFilterList() {
218 return attrFilterList;
219 }
220 }