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 com.unboundid.asn1.ASN1Element;
026    import com.unboundid.asn1.ASN1OctetString;
027    import com.unboundid.asn1.ASN1Sequence;
028    import com.unboundid.ldap.sdk.Control;
029    import com.unboundid.ldap.sdk.LDAPException;
030    import com.unboundid.ldap.sdk.ResultCode;
031    import com.unboundid.util.NotMutable;
032    import com.unboundid.util.StaticUtils;
033    import com.unboundid.util.ThreadSafety;
034    import com.unboundid.util.ThreadSafetyLevel;
035    
036    import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
037    import static com.unboundid.util.Debug.*;
038    import static com.unboundid.util.Validator.*;
039    
040    
041    
042    /**
043     * <BLOCKQUOTE>
044     *   <B>NOTE:</B>  This class is part of the Commercial Edition of the UnboundID
045     *   LDAP SDK for Java.  It is not available for use in applications that
046     *   include only the Standard Edition of the LDAP SDK, and is not supported for
047     *   use in conjunction with non-UnboundID products.
048     * </BLOCKQUOTE>
049     * This class provides an implementation of the get effective rights request
050     * control, which may be included in a search request to indicate that matching
051     * entries should include information about the rights a given user may have
052     * when interacting with that entry.
053     * <BR><BR>
054     * When the get effective rights control is included in a search request, then
055     * each entry returned may include information about the rights that the
056     * specified user has for that entry in the {@code aclRights} operational
057     * attribute.  Note that because this is an operational attribute, it must be
058     * explicitly included in the set of attributes to return.
059     * <BR><BR>
060     * If the {@code aclRights} attribute is included in the entry, then it will be
061     * present with multiple sets of options.  In one case, it will have an option
062     * of "entryLevel", which provides information about the rights that the user
063     * has for the entry in general (see the {@link EntryRight} enum for a list of
064     * the entry-level rights that can be held).  In all other cases, it will have
065     * one option of "attributeLevel" and another option that is the name of the
066     * attribute for which the set of rights is granted (see the
067     * {@link AttributeRight} enum for a list of the attribute-level rights that can
068     * be held).  In either case, the value will be a comma-delimited list of
069     * right strings, where each right string is the name of the right followed by
070     * a colon and a one to indicate that the right is granted or zero to indicate
071     * that it is not granted.  The {@link EffectiveRightsEntry} class provides a
072     * simple means of accessing the information encoded in the values of the
073     * {@code aclRights} attribute.
074     * <BR><BR>
075     * This control was designed by Sun Microsystems, and it is not the same as the
076     * get effective rights control referenced in the draft-ietf-ldapext-acl-model
077     * Internet draft.  The value for this control should be encoded as follows:
078     * <BR><BR>
079     * <PRE>
080     * GET_EFFECTIVE_RIGHTS := SEQUENCE {
081     *   authzID     authzID,
082     *   attributes  SEQUENCE OF AttributeType OPTIONAL }
083     * </PRE>
084     * <H2>Example</H2>
085     * The following example demonstrates the use of the get effective rights
086     * control to determine whether user "uid=admin,dc=example,dc=com" has the
087     * ability to change the password for the user with uid "john.doe":
088     * <PRE>
089     * SearchRequest searchRequest = new SearchRequest("dc=example,dc=com",
090     *      SearchScope.SUB, Filter.createEqualityFilter("uid", "john.doe"),
091     *      "userPassword", "aclRights");
092     * searchRequest.addControl(new GetEffectiveRightsRequestControl(
093     *      "dn:uid=admin,dc=example,dc=com"));
094     * SearchResult searchResult = connection.search(searchRequest);
095     *
096     * for (SearchResultEntry entry : searchResult.getSearchEntries())
097     * {
098     *   EffectiveRightsEntry effectiveRightsEntry =
099     *        new EffectiveRightsEntry(entry);
100     *   if (effectiveRightsEntry.rightsInformationAvailable())
101     *   {
102     *     if (effectiveRightsEntry.hasAttributeRight(AttributeRight.WRITE,
103     *          "userPassword"))
104     *     {
105     *       // The admin user has permission to change the target user's password.
106     *     }
107     *     else
108     *     {
109     *       // The admin user does not have permission to change the target user's
110     *       // password.
111     *     }
112     *   }
113     *   else
114     *   {
115     *     // No effective rights information was returned.
116     *   }
117     * }
118     * </PRE>
119     */
120    @NotMutable()
121    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
122    public final class GetEffectiveRightsRequestControl
123           extends Control
124    {
125      /**
126       * The OID (1.3.6.1.4.1.42.2.27.9.5.2) for the get effective rights request
127       * control.
128       */
129      public static final String GET_EFFECTIVE_RIGHTS_REQUEST_OID =
130           "1.3.6.1.4.1.42.2.27.9.5.2";
131    
132    
133    
134      /**
135       * The serial version UID for this serializable class.
136       */
137      private static final long serialVersionUID = 354733122036206073L;
138    
139    
140    
141      // The authorization ID of the user for which to calculate the effective
142      // rights.
143      private final String authzID;
144    
145      // The names of the attribute types for which to calculate the effective
146      // rights.
147      private final String[] attributes;
148    
149    
150    
151      /**
152       * Creates a new get effective rights request control with the provided
153       * information.  It will not be marked critical.
154       *
155       * @param  authzID     The authorization ID of the user for whom the effective
156       *                     rights should be calculated.  It must not be
157       *                     {@code null}.
158       * @param  attributes  The set of attributes for which to calculate the
159       *                     effective rights.
160       */
161      public GetEffectiveRightsRequestControl(final String authzID,
162                                              final String... attributes)
163      {
164        this(false, authzID, attributes);
165      }
166    
167    
168    
169      /**
170       * Creates a new get effective rights request control with the provided
171       * information.  It will not be marked critical.
172       *
173       * @param  isCritical  Indicates whether this control should be marked
174       *                     critical.
175       * @param  authzID     The authorization ID of the user for whom the effective
176       *                     rights should be calculated.  It must not be
177       *                     {@code null}.
178       * @param  attributes  The set of attributes for which to calculate the
179       *                     effective rights.
180       */
181      public GetEffectiveRightsRequestControl(final boolean isCritical,
182                                              final String authzID,
183                                              final String... attributes)
184      {
185        super(GET_EFFECTIVE_RIGHTS_REQUEST_OID, isCritical,
186              encodeValue(authzID, attributes));
187    
188        this.authzID    = authzID;
189        this.attributes = attributes;
190      }
191    
192    
193    
194      /**
195       * Creates a new get effective rights request control which is decoded from
196       * the provided generic control.
197       *
198       * @param  control  The generic control to be decoded as a get effective
199       *                  rights request control.
200       *
201       * @throws  LDAPException  If the provided control cannot be decoded as a get
202       *                         effective rights request control.
203       */
204      public GetEffectiveRightsRequestControl(final Control control)
205             throws LDAPException
206      {
207        super(control);
208    
209        final ASN1OctetString value = control.getValue();
210        if (value == null)
211        {
212          throw new LDAPException(ResultCode.DECODING_ERROR,
213                                  ERR_GER_REQUEST_NO_VALUE.get());
214        }
215    
216        final ASN1Element[] elements;
217        try
218        {
219          final ASN1Element valueElement = ASN1Element.decode(value.getValue());
220          elements = ASN1Sequence.decodeAsSequence(valueElement).elements();
221        }
222        catch (Exception e)
223        {
224          debugException(e);
225          throw new LDAPException(ResultCode.DECODING_ERROR,
226                                  ERR_GER_REQUEST_VALUE_NOT_SEQUENCE.get(e), e);
227        }
228    
229        if ((elements.length < 1) || (elements.length > 2))
230        {
231          throw new LDAPException(ResultCode.DECODING_ERROR,
232                                  ERR_GER_REQUEST_INVALID_ELEMENT_COUNT.get(
233                                       elements.length));
234        }
235    
236        authzID = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
237    
238        if (elements.length == 2)
239        {
240          try
241          {
242            final ASN1Element[] attrElements =
243                 ASN1Sequence.decodeAsSequence(elements[1]).elements();
244            attributes = new String[attrElements.length];
245            for (int i=0; i < attrElements.length; i++)
246            {
247              attributes[i] = ASN1OctetString.decodeAsOctetString(
248                                   attrElements[i]).stringValue();
249            }
250          }
251          catch (Exception e)
252          {
253            debugException(e);
254            throw new LDAPException(ResultCode.DECODING_ERROR,
255                                    ERR_GER_REQUEST_CANNOT_DECODE.get(e), e);
256          }
257        }
258        else
259        {
260          attributes = StaticUtils.NO_STRINGS;
261        }
262      }
263    
264    
265    
266      /**
267       * Encodes the provided information into an ASN.1 octet string suitable for
268       * use as the value of this control.
269       *
270       * @param  authzID     The authorization ID of the user for whom the effective
271       *                     rights should be calculated.  It must not be
272       *                     {@code null}.
273       * @param  attributes  The set of attributes for which to calculate the
274       *                     effective rights.
275       *
276       * @return  An ASN.1 octet string containing the encoded control value.
277       */
278      private static ASN1OctetString encodeValue(final String authzID,
279                                                 final String[] attributes)
280      {
281        ensureNotNull(authzID);
282    
283        final ASN1Element[] elements;
284        if ((attributes == null) || (attributes.length == 0))
285        {
286          elements = new ASN1Element[]
287          {
288            new ASN1OctetString(authzID),
289            new ASN1Sequence()
290          };
291        }
292        else
293        {
294          final ASN1Element[] attrElements = new ASN1Element[attributes.length];
295          for (int i=0; i < attributes.length; i++)
296          {
297            attrElements[i] = new ASN1OctetString(attributes[i]);
298          }
299    
300          elements = new ASN1Element[]
301          {
302            new ASN1OctetString(authzID),
303            new ASN1Sequence(attrElements)
304          };
305        }
306    
307        return new ASN1OctetString(new ASN1Sequence(elements).encode());
308      }
309    
310    
311    
312      /**
313       * Retrieves the authorization ID of the user for whom to calculate the
314       * effective rights.
315       *
316       * @return  The authorization ID of the user for whom to calculate the
317       *          effective rights.
318       */
319      public String getAuthzID()
320      {
321        return authzID;
322      }
323    
324    
325    
326      /**
327       * Retrieves the names of the attributes for which to calculate the effective
328       * rights information.
329       *
330       * @return  The names of the attributes for which to calculate the effective
331       *          rights information, or an empty array if no attribute names were
332       *          specified.
333       */
334      public String[] getAttributes()
335      {
336        return attributes;
337      }
338    
339    
340    
341      /**
342       * {@inheritDoc}
343       */
344      @Override()
345      public String getControlName()
346      {
347        return INFO_CONTROL_NAME_GET_EFFECTIVE_RIGHTS_REQUEST.get();
348      }
349    
350    
351    
352      /**
353       * {@inheritDoc}
354       */
355      @Override()
356      public void toString(final StringBuilder buffer)
357      {
358        buffer.append("GetEffectiveRightsRequestControl(authzId='");
359        buffer.append(authzID);
360        buffer.append('\'');
361    
362        if (attributes.length > 0)
363        {
364          buffer.append(", attributes={");
365          for (int i=0; i < attributes.length; i++)
366          {
367            if (i > 0)
368            {
369              buffer.append(", ");
370            }
371    
372            buffer.append(attributes[i]);
373          }
374          buffer.append('}');
375        }
376    
377        buffer.append(", isCritical=");
378        buffer.append(isCritical());
379        buffer.append(')');
380      }
381    }