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.StringTokenizer; 034 import java.util.LinkedHashSet; 035 import java.util.regex.Pattern; 036 import java.util.regex.Matcher; 037 038 import org.opends.server.core.DirectoryServer; 039 import org.opends.server.types.AttributeType; 040 import org.opends.server.types.DN; 041 import org.opends.server.types.LDAPURL; 042 import org.opends.server.types.DirectoryException; 043 044 /** 045 * This class is used by USERDN and GROUPDN userattr types 046 * to determine what parent inheritance checks to make. 047 */ 048 public class ParentInheritance { 049 050 /* 051 * The maximum number of parent inheritance levels supported. 052 */ 053 private static final int MAX_LEVELS=10; 054 055 /* 056 * Pattern to match for parent inheritance. 057 */ 058 private final String parentPat="parent["; 059 060 /* 061 * Array used to hold the level information. Each slot corresponds to a 062 * level parsed from the rule. 063 */ 064 private final int[] levels=new int[MAX_LEVELS]; 065 066 /* 067 * The number of levels parsed. 068 */ 069 private int numLevels; 070 071 /* 072 * The attribute type string parsed from the rule. Only used in 073 * inheritance search. 074 */ 075 private String attrTypeStr; 076 077 /* 078 * The base DN of a URL parsed from the rule. Used to make sure groupdn 079 * are under this suffix. Originally a way to search all nested groups 080 * under this suffix, so the behavior is slightly different. 081 */ 082 private DN baseDN=null; 083 084 085 /** 086 * Construct a class from the inheritance pattern. The skipParsing boolean 087 * specifies that parent parsing should be skipped and sets up the class: 088 * with numLevels=1, level[0]=0 and an attribute type from the 089 * specified pattern. 090 * 091 * @param pattern The string pattern containing the inheritance 092 * information. 093 * @param skipParse Specify if the parent inheritance parsing should be 094 * skipped or not. 095 * @throws AciException If the pattern is invalid. 096 */ 097 ParentInheritance (String pattern, boolean skipParse) throws AciException { 098 if (skipParse) { 099 //The "parent[" pattern is invalid for ROLEDN user attr keyword. 100 if(pattern.startsWith(parentPat)) { 101 Message message = 102 WARN_ACI_SYNTAX_INVALID_USERATTR_ROLEDN_INHERITANCE_PATTERN 103 .get(pattern); 104 throw new AciException(message); 105 } else { 106 pattern=pattern.trim(); 107 Pattern pattern1=Pattern.compile(ATTR_NAME); 108 Matcher matcher=pattern1.matcher(pattern); 109 //Check if valid attribute type name. 110 if(!matcher.find() || matcher.groupCount() != 1) { 111 Message message = 112 WARN_ACI_SYNTAX_INVALID_ATTRIBUTE_TYPE_NAME.get(pattern); 113 throw new AciException(message); 114 } 115 numLevels=1; 116 levels[0]=0; 117 } 118 } else parse(pattern); 119 } 120 121 /** 122 * Performs all parsing of the specified pattern string. 123 * @param pattern The string pattern containing the inheritance 124 * information. 125 * @throws AciException If the pattern is invalid. 126 */ 127 private void parse (String pattern) throws AciException { 128 pattern=pattern.trim(); 129 /** 130 * Check if we have a "parent[" string. 131 */ 132 if(pattern.startsWith(parentPat)) { 133 numLevels=0; 134 levels[0]=0; 135 String p=pattern.substring(parentPat.length()); 136 /** 137 * Format needs to be parent[XX].attribute -- everything after the 138 * '.' is the attribute type. 139 */ 140 String[] toks=p.split("\\."); 141 if(toks.length != 2) { 142 Message message = 143 WARN_ACI_SYNTAX_INVALID_USERATTR_INHERITANCE_PATTERN 144 .get(pattern); 145 throw new AciException(message); 146 } 147 Pattern pattern1=Pattern.compile(ATTR_NAME); 148 Matcher matcher=pattern1.matcher(toks[1]); 149 //Check if valid attribute type name. 150 if(!matcher.find() || matcher.groupCount() != 1) { 151 Message message = 152 WARN_ACI_SYNTAX_INVALID_ATTRIBUTE_TYPE_NAME.get(toks[1]); 153 throw new AciException(message); 154 } 155 attrTypeStr=toks[1]; 156 StringTokenizer tok=new StringTokenizer(toks[0],"],",false); 157 while(tok.hasMoreTokens()) { 158 String v=tok.nextToken(); 159 /** 160 * Everything between the brackets must be an integer or it's 161 * an error. 162 */ 163 try { 164 if(numLevels < MAX_LEVELS) { 165 levels[numLevels++]=Integer.decode(v); 166 } else { 167 Message message = 168 WARN_ACI_SYNTAX_MAX_USERATTR_INHERITANCE_LEVEL_EXCEEDED. 169 get(pattern, Integer.toString(MAX_LEVELS)); 170 throw new AciException(message); 171 } 172 } catch (NumberFormatException ex) { 173 Message message = 174 WARN_ACI_SYNTAX_INVALID_INHERITANCE_VALUE.get(pattern); 175 throw new AciException(message); 176 } 177 } 178 } else { 179 attrTypeStr=pattern; 180 if(pattern.startsWith(NULL_LDAP_URL)) { 181 try { 182 LDAPURL url=LDAPURL.decode(pattern, true); 183 LinkedHashSet<String>attrs=url.getAttributes(); 184 if(attrs.size() != 1) { 185 Message message = 186 WARN_ACI_SYNTAX_INVALID_USERATTR_ATTR_URL.get(pattern); 187 throw new AciException(message); 188 } 189 baseDN=url.getBaseDN(); 190 if(baseDN.isNullDN()){ 191 Message message = 192 WARN_ACI_SYNTAX_INVALID_USERATTR_BASEDN_URL.get(pattern); 193 throw new AciException(message); 194 } 195 attrTypeStr=attrs.iterator().next(); 196 } catch (DirectoryException ex) { 197 Message message = WARN_ACI_SYNTAX_INVALID_USERATTR_URL.get( 198 ex.getMessageObject()); 199 throw new AciException(message); 200 } 201 } 202 numLevels=1; 203 levels[0]=0; 204 } 205 } 206 207 /** 208 * Returns the number of levels counted. 209 * @return The number of levels. 210 */ 211 public int getNumLevels() { 212 return numLevels; 213 } 214 215 /** 216 * Returns an array of levels, where levels are integers. 217 * @return Return an array of levels. 218 */ 219 public int[] getLevels() { 220 int[] levelsCopy = new int[levels.length]; 221 System.arraycopy(levels, 0, levelsCopy, 0, levels.length); 222 return levelsCopy; 223 } 224 225 /** 226 * Return the attribute type. 227 * @return The attribute type. 228 */ 229 public AttributeType getAttributeType() { 230 AttributeType attrType; 231 if((attrType = 232 DirectoryServer.getAttributeType(attrTypeStr.toLowerCase())) == null) 233 attrType= 234 DirectoryServer.getDefaultAttributeType(attrTypeStr.toLowerCase()); 235 return attrType; 236 } 237 238 /** 239 * Return the string representation of the attribute type. 240 * @return The attribute type string. 241 */ 242 public String getAttrTypeStr() { 243 return attrTypeStr; 244 } 245 246 /** 247 * Return the DN that groupdn must be under. 248 * 249 * @return DN that groupdn must be under. 250 */ 251 public DN getBaseDN() { 252 return baseDN; 253 } 254 } 255