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    }