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 }