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