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.ArrayList;
026    import java.util.Arrays;
027    import java.util.Collections;
028    import java.util.Iterator;
029    import java.util.List;
030    
031    import com.unboundid.asn1.ASN1Boolean;
032    import com.unboundid.asn1.ASN1Element;
033    import com.unboundid.asn1.ASN1OctetString;
034    import com.unboundid.asn1.ASN1Sequence;
035    import com.unboundid.ldap.sdk.Control;
036    import com.unboundid.ldap.sdk.LDAPException;
037    import com.unboundid.ldap.sdk.ResultCode;
038    import com.unboundid.util.NotMutable;
039    import com.unboundid.util.ThreadSafety;
040    import com.unboundid.util.ThreadSafetyLevel;
041    
042    import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
043    import static com.unboundid.util.Debug.*;
044    import static com.unboundid.util.StaticUtils.*;
045    
046    
047    
048    /**
049     * <BLOCKQUOTE>
050     *   <B>NOTE:</B>  This class is part of the Commercial Edition of the UnboundID
051     *   LDAP SDK for Java.  It is not available for use in applications that
052     *   include only the Standard Edition of the LDAP SDK, and is not supported for
053     *   use in conjunction with non-UnboundID products.
054     * </BLOCKQUOTE>
055     * This class provides an implementation of an LDAP control that can be included
056     * in a bind request to request that the Directory Server return the
057     * authentication and authorization entries for the user that authenticated.
058     * The value of this control may be absent, but if it is present then will be
059     * encoded as follows:
060     * <PRE>
061     *   GetAuthorizationEntryRequest ::= SEQUENCE {
062     *        includeAuthNEntry     [0] BOOLEAN DEFAULT TRUE,
063     *        includeAuthZEntry     [1] BOOLEAN DEFAULT TRUE,
064     *        attributes            [2] AttributeSelection OPTIONAL }
065     * </PRE>
066     * <BR><BR>
067     * <H2>Example</H2>
068     * The following example demonstrates the process for processing a bind
069     * operation using the get authorization entry request control to return all
070     * user attributes in both the authentication and authorization entries:
071     * <PRE>
072     * ReadOnlyEntry authNEntry = null;
073     * ReadOnlyEntry authZEntry = null;
074     *
075     * BindRequest bindRequest = new SimpleBindRequest(
076     *      "uid=john.doe,ou=People,dc=example,dc=com", "password",
077     *      new GetAuthorizationEntryRequestControl());
078     *
079     * BindResult bindResult = connection.bind(bindRequest);
080     * GetAuthorizationEntryResponseControl c =
081     *      GetAuthorizationEntryResponseControl.get(bindResult);
082     * if (c != null)
083     * {
084     *   authNEntry = c.getAuthNEntry();
085     *   authZEntry = c.getAuthZEntry();
086     * }
087     * </PRE>
088     */
089    @NotMutable()
090    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
091    public final class GetAuthorizationEntryRequestControl
092           extends Control
093    {
094      /**
095       * The OID (1.3.6.1.4.1.30221.2.5.6) for the get authorization entry request
096       * control.
097       */
098      public static final String GET_AUTHORIZATION_ENTRY_REQUEST_OID =
099           "1.3.6.1.4.1.30221.2.5.6";
100    
101    
102    
103      /**
104       * The BER type for the {@code includeAuthNEntry} element.
105       */
106      private static final byte TYPE_INCLUDE_AUTHN_ENTRY = (byte) 0x80;
107    
108    
109    
110      /**
111       * The BER type for the {@code includeAuthZEntry} element.
112       */
113      private static final byte TYPE_INCLUDE_AUTHZ_ENTRY = (byte) 0x81;
114    
115    
116    
117      /**
118       * The BER type for the {@code attributes} element.
119       */
120      private static final byte TYPE_ATTRIBUTES = (byte) 0xA2;
121    
122    
123    
124      /**
125       * The serial version UID for this serializable class.
126       */
127      private static final long serialVersionUID = -5540345171260624216L;
128    
129    
130    
131      // Indicates whether to include the authentication entry in the response.
132      private final boolean includeAuthNEntry;
133    
134      // Indicates whether to include the authorization entry in the response.
135      private final boolean includeAuthZEntry;
136    
137      // The list of attributes to include in entries that are returned.
138      private final List<String> attributes;
139    
140    
141    
142      /**
143       * Creates a new get authorization entry request control that will request all
144       * user attributes in both the authentication and authorization entries.  It
145       * will not be marked critical.
146       */
147      public GetAuthorizationEntryRequestControl()
148      {
149        this(false, true, true, (List<String>) null);
150      }
151    
152    
153    
154      /**
155       * Creates a new get authorization entry request control with the provided
156       * information.
157       *
158       * @param  includeAuthNEntry  Indicates whether to include the authentication
159       *                            entry in the response.
160       * @param  includeAuthZEntry  Indicates whether to include the authorization
161       *                            entry in the response.
162       * @param  attributes         The attributes to include in the entries in the
163       *                            response.  It may be empty or {@code null} to
164       *                            request all user attributes.
165       */
166      public GetAuthorizationEntryRequestControl(final boolean includeAuthNEntry,
167                                                 final boolean includeAuthZEntry,
168                                                 final String... attributes)
169      {
170        this(false, includeAuthNEntry, includeAuthZEntry,
171             (attributes == null) ? null : Arrays.asList(attributes));
172      }
173    
174    
175    
176      /**
177       * Creates a new get authorization entry request control with the provided
178       * information.
179       *
180       * @param  includeAuthNEntry  Indicates whether to include the authentication
181       *                            entry in the response.
182       * @param  includeAuthZEntry  Indicates whether to include the authorization
183       *                            entry in the response.
184       * @param  attributes         The attributes to include in the entries in the
185       *                            response.  It may be empty or {@code null} to
186       *                            request all user attributes.
187       */
188      public GetAuthorizationEntryRequestControl(final boolean includeAuthNEntry,
189                                                 final boolean includeAuthZEntry,
190                                                 final List<String> attributes)
191      {
192        this(false, includeAuthNEntry, includeAuthZEntry, attributes);
193      }
194    
195    
196    
197      /**
198       * Creates a new get authorization entry request control with the provided
199       * information.
200       *
201       * @param  isCritical         Indicates whether the control should be marked
202       *                            critical.
203       * @param  includeAuthNEntry  Indicates whether to include the authentication
204       *                            entry in the response.
205       * @param  includeAuthZEntry  Indicates whether to include the authorization
206       *                            entry in the response.
207       * @param  attributes         The attributes to include in the entries in the
208       *                            response.  It may be empty or {@code null} to
209       *                            request all user attributes.
210       */
211      public GetAuthorizationEntryRequestControl(final boolean isCritical,
212                                                 final boolean includeAuthNEntry,
213                                                 final boolean includeAuthZEntry,
214                                                 final String... attributes)
215      {
216        this(isCritical, includeAuthNEntry, includeAuthZEntry,
217             (attributes == null) ? null : Arrays.asList(attributes));
218      }
219    
220    
221    
222      /**
223       * Creates a new get authorization entry request control with the provided
224       * information.
225       *
226       * @param  isCritical         Indicates whether the control should be marked
227       *                            critical.
228       * @param  includeAuthNEntry  Indicates whether to include the authentication
229       *                            entry in the response.
230       * @param  includeAuthZEntry  Indicates whether to include the authorization
231       *                            entry in the response.
232       * @param  attributes         The attributes to include in the entries in the
233       *                            response.  It may be empty or {@code null} to
234       *                            request all user attributes.
235       */
236      public GetAuthorizationEntryRequestControl(final boolean isCritical,
237                                                 final boolean includeAuthNEntry,
238                                                 final boolean includeAuthZEntry,
239                                                 final List<String> attributes)
240      {
241        super(GET_AUTHORIZATION_ENTRY_REQUEST_OID, isCritical,
242              encodeValue(includeAuthNEntry, includeAuthZEntry, attributes));
243    
244        this.includeAuthNEntry = includeAuthNEntry;
245        this.includeAuthZEntry = includeAuthZEntry;
246    
247        if ((attributes == null) || attributes.isEmpty())
248        {
249          this.attributes = Collections.emptyList();
250        }
251        else
252        {
253          this.attributes =
254               Collections.unmodifiableList(new ArrayList<String>(attributes));
255        }
256      }
257    
258    
259    
260      /**
261       * Creates a new get authorization entry request control which is decoded from
262       * the provided generic control.
263       *
264       * @param  control  The generic control to decode as a get authorization entry
265       *                  request control.
266       *
267       * @throws  LDAPException  If the provided control cannot be decoded as a get
268       *                         authorization entry request control.
269       */
270      public GetAuthorizationEntryRequestControl(final Control control)
271             throws LDAPException
272      {
273        super(control);
274    
275        final ASN1OctetString value = control.getValue();
276        if (value == null)
277        {
278          includeAuthNEntry = true;
279          includeAuthZEntry = true;
280          attributes        = Collections.emptyList();
281          return;
282        }
283    
284        try
285        {
286          final ArrayList<String> attrs = new ArrayList<String>();
287          boolean includeAuthN = true;
288          boolean includeAuthZ = true;
289    
290          final ASN1Element element = ASN1Element.decode(value.getValue());
291          for (final ASN1Element e :
292               ASN1Sequence.decodeAsSequence(element).elements())
293          {
294            switch (e.getType())
295            {
296              case TYPE_INCLUDE_AUTHN_ENTRY:
297                includeAuthN = ASN1Boolean.decodeAsBoolean(e).booleanValue();
298                break;
299              case TYPE_INCLUDE_AUTHZ_ENTRY:
300                includeAuthZ = ASN1Boolean.decodeAsBoolean(e).booleanValue();
301                break;
302              case TYPE_ATTRIBUTES:
303                for (final ASN1Element ae :
304                     ASN1Sequence.decodeAsSequence(e).elements())
305                {
306                  attrs.add(ASN1OctetString.decodeAsOctetString(ae).stringValue());
307                }
308                break;
309              default:
310                throw new LDAPException(ResultCode.DECODING_ERROR,
311                     ERR_GET_AUTHORIZATION_ENTRY_REQUEST_INVALID_SEQUENCE_ELEMENT.
312                          get(toHex(e.getType())));
313            }
314          }
315    
316          includeAuthNEntry = includeAuthN;
317          includeAuthZEntry = includeAuthZ;
318          attributes        = attrs;
319        }
320        catch (LDAPException le)
321        {
322          throw le;
323        }
324        catch (Exception e)
325        {
326          debugException(e);
327          throw new LDAPException(ResultCode.DECODING_ERROR,
328               ERR_GET_AUTHORIZATION_ENTRY_REQUEST_CANNOT_DECODE_VALUE.get(
329                    getExceptionMessage(e)), e);
330        }
331      }
332    
333    
334    
335      /**
336       * Encodes the provided information as appropriate for use as the value of
337       * this control.
338       *
339       * @param  includeAuthNEntry  Indicates whether to include the authentication
340       *                            entry in the response.
341       * @param  includeAuthZEntry  Indicates whether to include the authorization
342       *                            entry in the response.
343       * @param  attributes         The attributes to include in the entries in the
344       *                            response.  It may be empty or {@code null} to
345       *                            request all user attributes.
346       *
347       * @return  An ASN.1 octet string appropriately encoded for use as the control
348       *          value, or {@code null} if no value is needed.
349       */
350      private static ASN1OctetString encodeValue(final boolean includeAuthNEntry,
351                                                 final boolean includeAuthZEntry,
352                                                 final List<String> attributes)
353      {
354        if (includeAuthNEntry && includeAuthZEntry &&
355            ((attributes == null) || attributes.isEmpty()))
356        {
357          return null;
358        }
359    
360        final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3);
361    
362        if (! includeAuthNEntry)
363        {
364          elements.add(new ASN1Boolean(TYPE_INCLUDE_AUTHN_ENTRY, false));
365        }
366    
367        if (! includeAuthZEntry)
368        {
369          elements.add(new ASN1Boolean(TYPE_INCLUDE_AUTHZ_ENTRY, false));
370        }
371    
372        if ((attributes != null) && (! attributes.isEmpty()))
373        {
374          final ArrayList<ASN1Element> attrElements =
375               new ArrayList<ASN1Element>(attributes.size());
376          for (final String s : attributes)
377          {
378            attrElements.add(new ASN1OctetString(s));
379          }
380    
381          elements.add(new ASN1Sequence(TYPE_ATTRIBUTES, attrElements));
382        }
383    
384        return new ASN1OctetString(new ASN1Sequence(elements).encode());
385      }
386    
387    
388    
389      /**
390       * Indicates whether the entry for the authenticated user should be included
391       * in the response control.
392       *
393       * @return  {@code true} if the entry for the authenticated user should be
394       *          included in the response control, or {@code false} if not.
395       */
396      public boolean includeAuthNEntry()
397      {
398        return includeAuthNEntry;
399      }
400    
401    
402    
403      /**
404       * Indicates whether the entry for the authorized user should be included
405       * in the response control.
406       *
407       * @return  {@code true} if the entry for the authorized user should be
408       *          included in the response control, or {@code false} if not.
409       */
410      public boolean includeAuthZEntry()
411      {
412        return includeAuthZEntry;
413      }
414    
415    
416    
417      /**
418       * Retrieves the attributes that will be requested for the authentication
419       * and/or authorization entries.
420       *
421       * @return  The attributes that will be requested for the authentication
422       *          and/or authorization entries, or an empty list if all user
423       *          attributes should be included.
424       */
425      public List<String> getAttributes()
426      {
427        return attributes;
428      }
429    
430    
431    
432      /**
433       * {@inheritDoc}
434       */
435      @Override()
436      public String getControlName()
437      {
438        return INFO_CONTROL_NAME_GET_AUTHORIZATION_ENTRY_REQUEST.get();
439      }
440    
441    
442    
443      /**
444       * {@inheritDoc}
445       */
446      @Override()
447      public void toString(final StringBuilder buffer)
448      {
449        buffer.append("GetAuthorizationEntryRequestControl(isCritical=");
450        buffer.append(isCritical());
451        buffer.append(", includeAuthNEntry=");
452        buffer.append(includeAuthNEntry);
453        buffer.append(", includeAuthZEntry=");
454        buffer.append(includeAuthZEntry);
455        buffer.append(", attributes={");
456    
457        final Iterator<String> iterator = attributes.iterator();
458        while (iterator.hasNext())
459        {
460          buffer.append(iterator.next());
461          if (iterator.hasNext())
462          {
463            buffer.append(", ");
464          }
465        }
466    
467        buffer.append("})");
468      }
469    }