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    }