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