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