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.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 = new HashSet<>(1); 108 options.add("entryLevel"); 109 110 List<Attribute> attrList = 111 getAttributesWithOptions(ATTR_ACL_RIGHTS, options); 112 if ((attrList == null) || attrList.isEmpty()) 113 { 114 if (Debug.debugEnabled(DebugType.LDAP)) 115 { 116 Debug.debug(Level.WARNING, DebugType.LDAP, 117 "No entry-level aclRights information contained in entry " + 118 entry.getDN()); 119 } 120 121 entryRights = null; 122 } 123 else 124 { 125 entryRights = Collections.unmodifiableSet(parseEntryRights(attrList)); 126 } 127 128 options.clear(); 129 options.add("attributeLevel"); 130 attrList = getAttributesWithOptions(ATTR_ACL_RIGHTS, options); 131 if ((attrList == null) || attrList.isEmpty()) 132 { 133 if (Debug.debugEnabled(DebugType.LDAP)) 134 { 135 Debug.debug(Level.WARNING, DebugType.LDAP, 136 "No attribute-level aclRights information contained in entry " + 137 entry.getDN()); 138 } 139 140 attributeRights = null; 141 } 142 else 143 { 144 final HashMap<String,Set<AttributeRight>> attrRightsMap = 145 new HashMap<>(attrList.size()); 146 for (final Attribute a : attrList) 147 { 148 final Set<String> attrOptions = a.getOptions(); 149 String attrName = null; 150 for (final String s : attrOptions) 151 { 152 if (! s.equalsIgnoreCase("attributeLevel")) 153 { 154 attrName = s; 155 } 156 } 157 158 if (attrName == null) 159 { 160 if (Debug.debugEnabled(DebugType.LDAP)) 161 { 162 Debug.debug(Level.WARNING, DebugType.LDAP, 163 "Unable to determine the target attribute name from " + 164 a.getName()); 165 } 166 } 167 else 168 { 169 final String lowerName = StaticUtils.toLowerCase(attrName); 170 final Set<AttributeRight> rights = parseAttributeRights(a); 171 attrRightsMap.put(lowerName, rights); 172 } 173 } 174 175 attributeRights = Collections.unmodifiableMap(attrRightsMap); 176 } 177 } 178 179 180 181 /** 182 * Parses the entry rights information from the entry. 183 * 184 * @param attrList The list of attributes to be parsed. 185 * 186 * @return The set of entry rights parsed from the entry. 187 */ 188 private static Set<EntryRight> parseEntryRights( 189 final List<Attribute> attrList) 190 { 191 final EnumSet<EntryRight> entryRightsSet = EnumSet.noneOf(EntryRight.class); 192 for (final Attribute a : attrList) 193 { 194 for (final String value : a.getValues()) 195 { 196 final StringTokenizer tokenizer = new StringTokenizer(value, ", "); 197 while (tokenizer.hasMoreTokens()) 198 { 199 final String token = tokenizer.nextToken(); 200 if (token.endsWith(":1")) 201 { 202 final String rightName = token.substring(0, token.length()-2); 203 final EntryRight r = EntryRight.forName(rightName); 204 if (r == null) 205 { 206 if (Debug.debugEnabled(DebugType.LDAP)) 207 { 208 Debug.debug(Level.WARNING, DebugType.LDAP, 209 "Unrecognized entry right " + rightName); 210 } 211 } 212 else 213 { 214 entryRightsSet.add(r); 215 } 216 } 217 } 218 } 219 } 220 221 return entryRightsSet; 222 } 223 224 225 226 /** 227 * Parses the attribute rights information from the provided attribute. 228 * 229 * @param a The attribute to be parsed. 230 * 231 * @return The set of attribute rights parsed from the provided attribute. 232 */ 233 private static Set<AttributeRight> parseAttributeRights(final Attribute a) 234 { 235 final EnumSet<AttributeRight> rightsSet = 236 EnumSet.noneOf(AttributeRight.class); 237 238 for (final String value : a.getValues()) 239 { 240 final StringTokenizer tokenizer = new StringTokenizer(value, ", "); 241 while (tokenizer.hasMoreTokens()) 242 { 243 final String token = tokenizer.nextToken(); 244 if (token.endsWith(":1")) 245 { 246 final String rightName = token.substring(0, token.length()-2); 247 final AttributeRight r = AttributeRight.forName(rightName); 248 if (r == null) 249 { 250 if (Debug.debugEnabled(DebugType.LDAP)) 251 { 252 Debug.debug(Level.WARNING, DebugType.LDAP, 253 "Unrecognized attribute right " + rightName); 254 } 255 } 256 else 257 { 258 rightsSet.add(r); 259 } 260 } 261 } 262 } 263 264 return rightsSet; 265 } 266 267 268 269 /** 270 * Indicates whether any access control rights information was contained in 271 * the entry. 272 * 273 * @return {@code true} if access control rights information was contained in 274 * the entry, or {@code false} if not. 275 */ 276 public boolean rightsInformationAvailable() 277 { 278 return ((entryRights != null) || (attributeRights != null)); 279 } 280 281 282 283 /** 284 * Retrieves the set of entry-level rights parsed from the entry. 285 * 286 * @return The set of entry-level rights parsed from the entry, or 287 * {@code null} if the entry did not have any entry-level rights 288 * information. 289 */ 290 public Set<EntryRight> getEntryRights() 291 { 292 return entryRights; 293 } 294 295 296 297 /** 298 * Indicates whether the specified entry right is granted for this entry. 299 * 300 * @param entryRight The entry right for which to make the determination. 301 * It must not be {@code null}. 302 * 303 * @return {@code true} if the entry included entry-level rights information 304 * and the specified entry right is granted, or {@code false} if not. 305 */ 306 public boolean hasEntryRight(final EntryRight entryRight) 307 { 308 Validator.ensureNotNull(entryRight); 309 310 return ((entryRights != null) && entryRights.contains(entryRight)); 311 } 312 313 314 315 /** 316 * Retrieves the set of attribute-level rights parsed from the entry, mapped 317 * from attribute name (in all lowercase characters) to the set of 318 * attribute-level rights for that attribute. 319 * 320 * @return The set of attribute-level rights parsed from the entry, or 321 * {@code null} if the entry did not have any attribute-level rights 322 * information. 323 */ 324 public Map<String,Set<AttributeRight>> getAttributeRights() 325 { 326 return attributeRights; 327 } 328 329 330 331 /** 332 * Retrieves the set of attribute-level rights parsed from the entry for the 333 * specified attribute. 334 * 335 * @param attributeName The name of the attribute for which to retrieve the 336 * attribute-level rights. It must not be 337 * {@code null}. 338 * 339 * @return The set of attribute-level rights for the specified attribute, or 340 * {@code null} if the entry did not include any attribute-level 341 * rights information for the specified attribute. 342 */ 343 public Set<AttributeRight> getAttributeRights(final String attributeName) 344 { 345 Validator.ensureNotNull(attributeName); 346 347 if (attributeRights == null) 348 { 349 return null; 350 } 351 352 return attributeRights.get(StaticUtils.toLowerCase(attributeName)); 353 } 354 355 356 357 /** 358 * Indicates whether the specified attribute right is granted for the 359 * specified attribute in this entry. 360 * 361 * @param attributeRight The attribute right for which to make the 362 * determination. It must not be {@code null}. 363 * @param attributeName The name of the attribute for which to make the 364 * determination. It must not be {@code null}. 365 * 366 * @return {@code true} if the entry included attribute-level rights 367 * information for the specified attribute and the indicated right is 368 * granted, or {@code false} if not. 369 */ 370 public boolean hasAttributeRight(final AttributeRight attributeRight, 371 final String attributeName) 372 { 373 Validator.ensureNotNull(attributeName, attributeRight); 374 375 final Set<AttributeRight> attrRights = getAttributeRights(attributeName); 376 return ((attrRights != null) && attrRights.contains(attributeRight)); 377 } 378}