001 /* 002 * Copyright 2008-2015 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005 /* 006 * Copyright (C) 2015 UnboundID Corp. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021 package com.unboundid.ldap.sdk.unboundidds.controls; 022 023 024 025 import java.util.Collections; 026 import java.util.EnumSet; 027 import java.util.HashMap; 028 import java.util.HashSet; 029 import java.util.List; 030 import java.util.Map; 031 import java.util.Set; 032 import java.util.StringTokenizer; 033 import java.util.logging.Level; 034 035 import com.unboundid.ldap.sdk.Attribute; 036 import com.unboundid.ldap.sdk.Entry; 037 import com.unboundid.ldap.sdk.ReadOnlyEntry; 038 import com.unboundid.util.DebugType; 039 import com.unboundid.util.NotMutable; 040 import com.unboundid.util.ThreadSafety; 041 import com.unboundid.util.ThreadSafetyLevel; 042 043 import static com.unboundid.util.Debug.*; 044 import static com.unboundid.util.StaticUtils.*; 045 import static com.unboundid.util.Validator.*; 046 047 048 049 /** 050 * <BLOCKQUOTE> 051 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID 052 * LDAP SDK for Java. It is not available for use in applications that 053 * include only the Standard Edition of the LDAP SDK, and is not supported for 054 * use in conjunction with non-UnboundID products. 055 * </BLOCKQUOTE> 056 * This class provides a mechanism for extracting the effective rights 057 * information from an entry returned for a search request that included the 058 * get effective rights request control. In particular, it provides the ability 059 * to parse the values of the aclRights attributes in order to determine what 060 * rights the specified user may have when interacting with the entry. 061 * <BR><BR> 062 * See the {@link GetEffectiveRightsRequestControl} for an example that 063 * demonstrates the use of the get effective rights request control and this 064 * entry. 065 */ 066 @NotMutable() 067 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 068 public final class EffectiveRightsEntry 069 extends ReadOnlyEntry 070 { 071 /** 072 * The name of the attribute that includes the rights information. 073 */ 074 private static final String ATTR_ACL_RIGHTS = "aclRights"; 075 076 077 078 /** 079 * The serial version UID for this serializable class. 080 */ 081 private static final long serialVersionUID = -3203127456449579174L; 082 083 084 085 // The set of entry-level rights parsed from the entry. 086 private final Set<EntryRight> entryRights; 087 088 // The set of attribute-level rights parsed from the entry, mapped from the 089 // name of the attribute to the set of the corresponding attribute rights. 090 private final Map<String,Set<AttributeRight>> attributeRights; 091 092 093 094 /** 095 * Creates a new get effective rights entry from the provided entry. 096 * 097 * @param entry The entry to use to create this get effective rights entry. 098 * It must not be {@code null}. 099 */ 100 public EffectiveRightsEntry(final Entry entry) 101 { 102 super(entry); 103 104 final HashSet<String> options = new HashSet<String>(1); 105 options.add("entryLevel"); 106 107 List<Attribute> attrList = 108 getAttributesWithOptions(ATTR_ACL_RIGHTS, options); 109 if ((attrList == null) || attrList.isEmpty()) 110 { 111 if (debugEnabled(DebugType.LDAP)) 112 { 113 debug(Level.WARNING, DebugType.LDAP, 114 "No entry-level aclRights information contained in entry " + 115 entry.getDN()); 116 } 117 118 entryRights = null; 119 } 120 else 121 { 122 entryRights = Collections.unmodifiableSet(parseEntryRights(attrList)); 123 } 124 125 options.clear(); 126 options.add("attributeLevel"); 127 attrList = getAttributesWithOptions(ATTR_ACL_RIGHTS, options); 128 if ((attrList == null) || attrList.isEmpty()) 129 { 130 if (debugEnabled(DebugType.LDAP)) 131 { 132 debug(Level.WARNING, DebugType.LDAP, 133 "No attribute-level aclRights information contained in entry " + 134 entry.getDN()); 135 } 136 137 attributeRights = null; 138 } 139 else 140 { 141 final HashMap<String,Set<AttributeRight>> attrRightsMap = 142 new HashMap<String,Set<AttributeRight>>(attrList.size()); 143 for (final Attribute a : attrList) 144 { 145 final Set<String> attrOptions = a.getOptions(); 146 String attrName = null; 147 for (final String s : attrOptions) 148 { 149 if (! s.equalsIgnoreCase("attributeLevel")) 150 { 151 attrName = s; 152 } 153 } 154 155 if (attrName == null) 156 { 157 if (debugEnabled(DebugType.LDAP)) 158 { 159 debug(Level.WARNING, DebugType.LDAP, 160 "Unable to determine the target attribute name from " + 161 a.getName()); 162 } 163 } 164 else 165 { 166 final String lowerName = toLowerCase(attrName); 167 final Set<AttributeRight> rights = parseAttributeRights(a); 168 attrRightsMap.put(lowerName, rights); 169 } 170 } 171 172 attributeRights = Collections.unmodifiableMap(attrRightsMap); 173 } 174 } 175 176 177 178 /** 179 * Parses the entry rights information from the entry. 180 * 181 * @param attrList The list of attributes to be parsed. 182 * 183 * @return The set of entry rights parsed from the entry. 184 */ 185 private static Set<EntryRight> parseEntryRights( 186 final List<Attribute> attrList) 187 { 188 final EnumSet<EntryRight> entryRightsSet = EnumSet.noneOf(EntryRight.class); 189 for (final Attribute a : attrList) 190 { 191 for (final String value : a.getValues()) 192 { 193 final StringTokenizer tokenizer = new StringTokenizer(value, ", "); 194 while (tokenizer.hasMoreTokens()) 195 { 196 final String token = tokenizer.nextToken(); 197 if (token.endsWith(":1")) 198 { 199 final String rightName = token.substring(0, token.length()-2); 200 final EntryRight r = EntryRight.forName(rightName); 201 if (r == null) 202 { 203 if (debugEnabled(DebugType.LDAP)) 204 { 205 debug(Level.WARNING, DebugType.LDAP, 206 "Unrecognized entry right " + rightName); 207 } 208 } 209 else 210 { 211 entryRightsSet.add(r); 212 } 213 } 214 } 215 } 216 } 217 218 return entryRightsSet; 219 } 220 221 222 223 /** 224 * Parses the attribute rights information from the provided attribute. 225 * 226 * @param a The attribute to be parsed. 227 * 228 * @return The set of attribute rights parsed from the provided attribute. 229 */ 230 private static Set<AttributeRight> parseAttributeRights(final Attribute a) 231 { 232 final EnumSet<AttributeRight> rightsSet = 233 EnumSet.noneOf(AttributeRight.class); 234 235 for (final String value : a.getValues()) 236 { 237 final StringTokenizer tokenizer = new StringTokenizer(value, ", "); 238 while (tokenizer.hasMoreTokens()) 239 { 240 final String token = tokenizer.nextToken(); 241 if (token.endsWith(":1")) 242 { 243 final String rightName = token.substring(0, token.length()-2); 244 final AttributeRight r = AttributeRight.forName(rightName); 245 if (r == null) 246 { 247 if (debugEnabled(DebugType.LDAP)) 248 { 249 debug(Level.WARNING, DebugType.LDAP, 250 "Unrecognized attribute right " + rightName); 251 } 252 } 253 else 254 { 255 rightsSet.add(r); 256 } 257 } 258 } 259 } 260 261 return rightsSet; 262 } 263 264 265 266 /** 267 * Indicates whether any access control rights information was contained in 268 * the entry. 269 * 270 * @return {@code true} if access control rights information was contained in 271 * the entry, or {@code false} if not. 272 */ 273 public boolean rightsInformationAvailable() 274 { 275 return ((entryRights != null) || (attributeRights != null)); 276 } 277 278 279 280 /** 281 * Retrieves the set of entry-level rights parsed from the entry. 282 * 283 * @return The set of entry-level rights parsed from the entry, or 284 * {@code null} if the entry did not have any entry-level rights 285 * information. 286 */ 287 public Set<EntryRight> getEntryRights() 288 { 289 return entryRights; 290 } 291 292 293 294 /** 295 * Indicates whether the specified entry right is granted for this entry. 296 * 297 * @param entryRight The entry right for which to make the determination. 298 * It must not be {@code null}. 299 * 300 * @return {@code true} if the entry included entry-level rights information 301 * and the specified entry right is granted, or {@code false} if not. 302 */ 303 public boolean hasEntryRight(final EntryRight entryRight) 304 { 305 ensureNotNull(entryRight); 306 307 return ((entryRights != null) && entryRights.contains(entryRight)); 308 } 309 310 311 312 /** 313 * Retrieves the set of attribute-level rights parsed from the entry, mapped 314 * from attribute name (in all lowercase characters) to the set of 315 * attribute-level rights for that attribute. 316 * 317 * @return The set of attribute-level rights parsed from the entry, or 318 * {@code null} if the entry did not have any attribute-level rights 319 * information. 320 */ 321 public Map<String,Set<AttributeRight>> getAttributeRights() 322 { 323 return attributeRights; 324 } 325 326 327 328 /** 329 * Retrieves the set of attribute-level rights parsed from the entry for the 330 * specified attribute. 331 * 332 * @param attributeName The name of the attribute for which to retrieve the 333 * attribute-level rights. It must not be 334 * {@code null}. 335 * 336 * @return The set of attribute-level rights for the specified attribute, or 337 * {@code null} if the entry did not include any attribute-level 338 * rights information for the specified attribute. 339 */ 340 public Set<AttributeRight> getAttributeRights(final String attributeName) 341 { 342 ensureNotNull(attributeName); 343 344 if (attributeRights == null) 345 { 346 return null; 347 } 348 349 return attributeRights.get(toLowerCase(attributeName)); 350 } 351 352 353 354 /** 355 * Indicates whether the specified attribute right is granted for the 356 * specified attribute in this entry. 357 * 358 * @param attributeRight The attribute right for which to make the 359 * determination. It must not be {@code null}. 360 * @param attributeName The name of the attribute for which to make the 361 * determination. It must not be {@code null}. 362 * 363 * @return {@code true} if the entry included attribute-level rights 364 * information for the specified attribute and the indicated right is 365 * granted, or {@code false} if not. 366 */ 367 public boolean hasAttributeRight(final AttributeRight attributeRight, 368 final String attributeName) 369 { 370 ensureNotNull(attributeName, attributeRight); 371 372 final Set<AttributeRight> attrRights = getAttributeRights(attributeName); 373 return ((attrRights != null) && attrRights.contains(attributeRight)); 374 } 375 }