001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2008 Sun Microsystems, Inc. 015 * Portions Copyright 2013-2016 ForgeRock AS. 016 */ 017package org.opends.server.authorization.dseecompat; 018 019import static org.opends.messages.AccessControlMessages.*; 020import static org.opends.server.authorization.dseecompat.Aci.*; 021 022import java.util.LinkedHashMap; 023import java.util.regex.Matcher; 024import java.util.regex.Pattern; 025 026import org.forgerock.i18n.LocalizableMessage; 027import org.opends.server.core.DirectoryServer; 028import org.forgerock.opendj.ldap.schema.AttributeType; 029import org.opends.server.types.DirectoryException; 030import org.opends.server.types.SearchFilter; 031 032/** 033 * The TargAttrFilterList class represents an targattrfilters list. A 034 * targattrfilters list looks like: 035 * 036 * "Op=attr1:F1 [(&& attr2:F2)*] 037 */ 038public class TargAttrFilterList { 039 040 /** 041 * The mask corresponding to the operation of this list (add or del). 042 */ 043 private int mask; 044 045 /** 046 * ListHashMap keyed by the attribute type and mapping to the corresponding 047 * search filter. LinkedHashMap is used so everything is in order. 048 */ 049 private LinkedHashMap<AttributeType, SearchFilter> attrFilterList; 050 051 /** 052 * Regular expression group count. 053 */ 054 private static int expectedGroupCount=2; 055 056 /** 057 * Regular expression attribute group position. 058 */ 059 private static int attributePos=1; 060 061 /** 062 * Regular expression filter group position. 063 */ 064 private static int filterPos=2; 065 066 /** 067 * Regular expression used to match a filter list including the strange "and" 068 * token used to join the multiple attribute type filter pairs. 069 */ 070 private static final String filterListSeperator = 071 ZERO_OR_MORE_WHITESPACE + "&&" + ZERO_OR_MORE_WHITESPACE; 072 073 /** 074 * Regular expression used to match an attribute filter pair. 075 */ 076 private static final String attributeFilter= 077 ATTR_NAME + ZERO_OR_MORE_WHITESPACE + ":{1}" + 078 ZERO_OR_MORE_WHITESPACE + "(\\({1}.*\\){1})"; 079 080 /** 081 * Construct a class representing an targattrfilters filter list. 082 * @param mask The mask representing the operation. 083 * @param attrFilterList The list map containing the attribute type 084 * filter mappings. 085 */ 086 public TargAttrFilterList(int mask, 087 LinkedHashMap<AttributeType, SearchFilter> attrFilterList) { 088 this.mask=mask; 089 this.attrFilterList=attrFilterList; 090 } 091 092 /** 093 * Decode an TargAttrFilterList from the specified expression string. 094 * @param mask The mask representing the operation. 095 * @param expression The expression string to decode. 096 * @return A TargAttrFilterList class representing the targattrfilters 097 * filter list. 098 * @throws AciException If the expression string contains errors. 099 */ 100 public static TargAttrFilterList decode(int mask, String expression) 101 throws AciException { 102 LinkedHashMap<AttributeType, SearchFilter> attrFilterList = new LinkedHashMap<>(); 103 String[] subExpressions=expression.split(filterListSeperator, -1); 104 //Iterate over each sub-expression, parse and add them to the list 105 //if there are no errors. 106 for(String subs : subExpressions) { 107 Pattern pattern=Pattern.compile(attributeFilter); 108 Matcher matcher=pattern.matcher(subs); 109 //Match the attribute:filter pair part of the expression 110 if(!matcher.find() || matcher.groupCount() != expectedGroupCount) { 111 LocalizableMessage message = 112 WARN_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LIST_FORMAT. 113 get(expression); 114 throw new AciException(message); 115 } 116 String attributeName=matcher.group(attributePos).toLowerCase(); 117 //Strip off any options, so it will match the filter option 118 //handling. 119 int semicolon = attributeName.indexOf(';'); 120 if (semicolon != -1) 121 { 122 attributeName=attributeName.substring(0, semicolon); 123 } 124 String filterString=matcher.group(filterPos); 125 AttributeType attrType = DirectoryServer.getAttributeType(attributeName); 126 SearchFilter filter; 127 //Check if it is a valid filter and add it to the list map if ok. 128 try { 129 filter = SearchFilter.createFilterFromString(filterString); 130 attrFilterList.put(attrType, filter); 131 } catch (DirectoryException ex) { 132 LocalizableMessage er=ex.getMessageObject(); 133 LocalizableMessage message = 134 WARN_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LISTS_FILTER. 135 get(filterString, er); 136 throw new AciException(message); 137 } 138 //Verify the filter components. This check assures that each 139 //attribute type in the filter matches the provided attribute type. 140 verifyFilterComponents(filter, attrType); 141 } 142 return new TargAttrFilterList(mask, attrFilterList); 143 } 144 145 /** 146 * Verify the filter component attribute types by assuring that each 147 * attribute type in the filter matches the specified attribute type. 148 * @param filter The filter to verify. 149 * @param type The attribute type to use in the verification. 150 * @throws AciException If the filter contains an attribute type not 151 * specified. 152 */ 153 private static void verifyFilterComponents(SearchFilter filter, 154 AttributeType type) 155 throws AciException { 156 switch (filter.getFilterType()) { 157 case AND: 158 case OR: { 159 for (SearchFilter f : filter.getFilterComponents()) { 160 verifyFilterComponents(f, type); 161 } 162 break; 163 } 164 case NOT: { 165 SearchFilter f = filter.getNotComponent(); 166 verifyFilterComponents(f, type); 167 break; 168 } 169 default: { 170 AttributeType attrType=filter.getAttributeType(); 171 if(!attrType.equals(type)) { 172 throw new AciException( 173 WARN_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LISTS_ATTR_FILTER.get(filter)); 174 } 175 } 176 } 177 } 178 179 /** 180 * Return the mask of this TargAttrFilterList. 181 * @return The mask value. 182 */ 183 public int getMask() { 184 return this.mask; 185 } 186 187 /** 188 * Check if the mask value of this TargAttrFilterList class contains the 189 * specified mask value. 190 * @param mask The mask to check for. 191 * @return True if the mask matches the specified value. 192 */ 193 public boolean hasMask(int mask) { 194 return (this.mask & mask) != 0; 195 } 196 197 /** 198 * Return the list map holding the attribute type to filter mappings. 199 * @return The list map. 200 */ 201 public 202 LinkedHashMap<AttributeType, SearchFilter> getAttributeTypeFilterList() { 203 return attrFilterList; 204 } 205}