001/*
002 * Copyright 2008-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2008-2024 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2008-2024 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.sdk.unboundidds.controls;
037
038
039
040import java.util.ArrayList;
041import java.util.Arrays;
042import java.util.Collections;
043import java.util.Iterator;
044import java.util.LinkedHashMap;
045import java.util.List;
046import java.util.Map;
047
048import com.unboundid.asn1.ASN1Boolean;
049import com.unboundid.asn1.ASN1Element;
050import com.unboundid.asn1.ASN1OctetString;
051import com.unboundid.asn1.ASN1Sequence;
052import com.unboundid.ldap.sdk.Control;
053import com.unboundid.ldap.sdk.JSONControlDecodeHelper;
054import com.unboundid.ldap.sdk.LDAPException;
055import com.unboundid.ldap.sdk.ResultCode;
056import com.unboundid.util.Debug;
057import com.unboundid.util.NotMutable;
058import com.unboundid.util.NotNull;
059import com.unboundid.util.Nullable;
060import com.unboundid.util.StaticUtils;
061import com.unboundid.util.ThreadSafety;
062import com.unboundid.util.ThreadSafetyLevel;
063import com.unboundid.util.json.JSONArray;
064import com.unboundid.util.json.JSONBoolean;
065import com.unboundid.util.json.JSONField;
066import com.unboundid.util.json.JSONObject;
067import com.unboundid.util.json.JSONString;
068import com.unboundid.util.json.JSONValue;
069
070import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
071
072
073
074/**
075 * This class provides an implementation of an LDAP control that can be included
076 * in a bind request to request that the Directory Server return the
077 * authentication and authorization entries for the user that authenticated.
078 * <BR>
079 * <BLOCKQUOTE>
080 *   <B>NOTE:</B>  This class, and other classes within the
081 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
082 *   supported for use against Ping Identity, UnboundID, and
083 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
084 *   for proprietary functionality or for external specifications that are not
085 *   considered stable or mature enough to be guaranteed to work in an
086 *   interoperable way with other types of LDAP servers.
087 * </BLOCKQUOTE>
088 * <BR>
089 * The value of this control may be absent, but if it is present then will be
090 * encoded as follows:
091 * <PRE>
092 *   GetAuthorizationEntryRequest ::= SEQUENCE {
093 *        includeAuthNEntry     [0] BOOLEAN DEFAULT TRUE,
094 *        includeAuthZEntry     [1] BOOLEAN DEFAULT TRUE,
095 *        attributes            [2] AttributeSelection OPTIONAL }
096 * </PRE>
097 * <BR><BR>
098 * <H2>Example</H2>
099 * The following example demonstrates the process for processing a bind
100 * operation using the get authorization entry request control to return all
101 * user attributes in both the authentication and authorization entries:
102 * <PRE>
103 * ReadOnlyEntry authNEntry = null;
104 * ReadOnlyEntry authZEntry = null;
105 *
106 * BindRequest bindRequest = new SimpleBindRequest(
107 *      "uid=john.doe,ou=People,dc=example,dc=com", "password",
108 *      new GetAuthorizationEntryRequestControl());
109 *
110 * BindResult bindResult = connection.bind(bindRequest);
111 * GetAuthorizationEntryResponseControl c =
112 *      GetAuthorizationEntryResponseControl.get(bindResult);
113 * if (c != null)
114 * {
115 *   authNEntry = c.getAuthNEntry();
116 *   authZEntry = c.getAuthZEntry();
117 * }
118 * </PRE>
119 */
120@NotMutable()
121@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
122public final class GetAuthorizationEntryRequestControl
123       extends Control
124{
125  /**
126   * The OID (1.3.6.1.4.1.30221.2.5.6) for the get authorization entry request
127   * control.
128   */
129  @NotNull public static final String GET_AUTHORIZATION_ENTRY_REQUEST_OID =
130       "1.3.6.1.4.1.30221.2.5.6";
131
132
133
134  /**
135   * The BER type for the {@code includeAuthNEntry} element.
136   */
137  private static final byte TYPE_INCLUDE_AUTHN_ENTRY = (byte) 0x80;
138
139
140
141  /**
142   * The BER type for the {@code includeAuthZEntry} element.
143   */
144  private static final byte TYPE_INCLUDE_AUTHZ_ENTRY = (byte) 0x81;
145
146
147
148  /**
149   * The BER type for the {@code attributes} element.
150   */
151  private static final byte TYPE_ATTRIBUTES = (byte) 0xA2;
152
153
154
155  /**
156   * The name of the field used to hold the names of the requested attributes in
157   * the JSON representation of this control.
158   */
159  @NotNull private static final String JSON_FIELD_ATTRIBUTES = "attributes";
160
161
162
163  /**
164   * The name of the field used to indicate whether to include the
165   * authentication entry in the JSON representation of this control.
166   */
167  @NotNull private static final String JSON_FIELD_INCLUDE_AUTHENTICATION_ENTRY =
168       "include-authentication-entry";
169
170
171
172  /**
173   * The name of the field used to indicate whether to include the
174   * authorization entry in the JSON representation of this control.
175   */
176  @NotNull private static final String JSON_FIELD_INCLUDE_AUTHORIZATION_ENTRY =
177       "include-authorization-entry";
178
179
180
181  /**
182   * The serial version UID for this serializable class.
183   */
184  private static final long serialVersionUID = -5540345171260624216L;
185
186
187
188  // Indicates whether to include the authentication entry in the response.
189  private final boolean includeAuthNEntry;
190
191  // Indicates whether to include the authorization entry in the response.
192  private final boolean includeAuthZEntry;
193
194  // The list of attributes to include in entries that are returned.
195  @NotNull private final List<String> attributes;
196
197
198
199  /**
200   * Creates a new get authorization entry request control that will request all
201   * user attributes in both the authentication and authorization entries.  It
202   * will not be marked critical.
203   */
204  public GetAuthorizationEntryRequestControl()
205  {
206    this(false, true, true, (List<String>) null);
207  }
208
209
210
211  /**
212   * Creates a new get authorization entry request control with the provided
213   * information.
214   *
215   * @param  includeAuthNEntry  Indicates whether to include the authentication
216   *                            entry in the response.
217   * @param  includeAuthZEntry  Indicates whether to include the authorization
218   *                            entry in the response.
219   * @param  attributes         The attributes to include in the entries in the
220   *                            response.  It may be empty or {@code null} to
221   *                            request all user attributes.
222   */
223  public GetAuthorizationEntryRequestControl(final boolean includeAuthNEntry,
224              final boolean includeAuthZEntry,
225              @Nullable final String... attributes)
226  {
227    this(false, includeAuthNEntry, includeAuthZEntry,
228         (attributes == null) ? null : Arrays.asList(attributes));
229  }
230
231
232
233  /**
234   * Creates a new get authorization entry request control with the provided
235   * information.
236   *
237   * @param  includeAuthNEntry  Indicates whether to include the authentication
238   *                            entry in the response.
239   * @param  includeAuthZEntry  Indicates whether to include the authorization
240   *                            entry in the response.
241   * @param  attributes         The attributes to include in the entries in the
242   *                            response.  It may be empty or {@code null} to
243   *                            request all user attributes.
244   */
245  public GetAuthorizationEntryRequestControl(final boolean includeAuthNEntry,
246              final boolean includeAuthZEntry,
247              @Nullable final List<String> attributes)
248  {
249    this(false, includeAuthNEntry, includeAuthZEntry, attributes);
250  }
251
252
253
254  /**
255   * Creates a new get authorization entry request control with the provided
256   * information.
257   *
258   * @param  isCritical         Indicates whether the control should be marked
259   *                            critical.
260   * @param  includeAuthNEntry  Indicates whether to include the authentication
261   *                            entry in the response.
262   * @param  includeAuthZEntry  Indicates whether to include the authorization
263   *                            entry in the response.
264   * @param  attributes         The attributes to include in the entries in the
265   *                            response.  It may be empty or {@code null} to
266   *                            request all user attributes.
267   */
268  public GetAuthorizationEntryRequestControl(final boolean isCritical,
269              final boolean includeAuthNEntry,
270              final boolean includeAuthZEntry,
271              @Nullable final String... attributes)
272  {
273    this(isCritical, includeAuthNEntry, includeAuthZEntry,
274         (attributes == null) ? null : Arrays.asList(attributes));
275  }
276
277
278
279  /**
280   * Creates a new get authorization entry request control with the provided
281   * information.
282   *
283   * @param  isCritical         Indicates whether the control should be marked
284   *                            critical.
285   * @param  includeAuthNEntry  Indicates whether to include the authentication
286   *                            entry in the response.
287   * @param  includeAuthZEntry  Indicates whether to include the authorization
288   *                            entry in the response.
289   * @param  attributes         The attributes to include in the entries in the
290   *                            response.  It may be empty or {@code null} to
291   *                            request all user attributes.
292   */
293  public GetAuthorizationEntryRequestControl(final boolean isCritical,
294              final boolean includeAuthNEntry,
295              final boolean includeAuthZEntry,
296              @Nullable final List<String> attributes)
297  {
298    super(GET_AUTHORIZATION_ENTRY_REQUEST_OID, isCritical,
299          encodeValue(includeAuthNEntry, includeAuthZEntry, attributes));
300
301    this.includeAuthNEntry = includeAuthNEntry;
302    this.includeAuthZEntry = includeAuthZEntry;
303
304    if ((attributes == null) || attributes.isEmpty())
305    {
306      this.attributes = Collections.emptyList();
307    }
308    else
309    {
310      this.attributes =
311           Collections.unmodifiableList(new ArrayList<>(attributes));
312    }
313  }
314
315
316
317  /**
318   * Creates a new get authorization entry request control which is decoded from
319   * the provided generic control.
320   *
321   * @param  control  The generic control to decode as a get authorization entry
322   *                  request control.
323   *
324   * @throws  LDAPException  If the provided control cannot be decoded as a get
325   *                         authorization entry request control.
326   */
327  public GetAuthorizationEntryRequestControl(@NotNull final Control control)
328         throws LDAPException
329  {
330    super(control);
331
332    final ASN1OctetString value = control.getValue();
333    if (value == null)
334    {
335      includeAuthNEntry = true;
336      includeAuthZEntry = true;
337      attributes        = Collections.emptyList();
338      return;
339    }
340
341    try
342    {
343      final ArrayList<String> attrs = new ArrayList<>(20);
344      boolean includeAuthN = true;
345      boolean includeAuthZ = true;
346
347      final ASN1Element element = ASN1Element.decode(value.getValue());
348      for (final ASN1Element e :
349           ASN1Sequence.decodeAsSequence(element).elements())
350      {
351        switch (e.getType())
352        {
353          case TYPE_INCLUDE_AUTHN_ENTRY:
354            includeAuthN = ASN1Boolean.decodeAsBoolean(e).booleanValue();
355            break;
356          case TYPE_INCLUDE_AUTHZ_ENTRY:
357            includeAuthZ = ASN1Boolean.decodeAsBoolean(e).booleanValue();
358            break;
359          case TYPE_ATTRIBUTES:
360            for (final ASN1Element ae :
361                 ASN1Sequence.decodeAsSequence(e).elements())
362            {
363              attrs.add(ASN1OctetString.decodeAsOctetString(ae).stringValue());
364            }
365            break;
366          default:
367            throw new LDAPException(ResultCode.DECODING_ERROR,
368                 ERR_GET_AUTHORIZATION_ENTRY_REQUEST_INVALID_SEQUENCE_ELEMENT.
369                      get(StaticUtils.toHex(e.getType())));
370        }
371      }
372
373      includeAuthNEntry = includeAuthN;
374      includeAuthZEntry = includeAuthZ;
375      attributes        = attrs;
376    }
377    catch (final LDAPException le)
378    {
379      throw le;
380    }
381    catch (final Exception e)
382    {
383      Debug.debugException(e);
384      throw new LDAPException(ResultCode.DECODING_ERROR,
385           ERR_GET_AUTHORIZATION_ENTRY_REQUEST_CANNOT_DECODE_VALUE.get(
386                StaticUtils.getExceptionMessage(e)),
387           e);
388    }
389  }
390
391
392
393  /**
394   * Encodes the provided information as appropriate for use as the value of
395   * this control.
396   *
397   * @param  includeAuthNEntry  Indicates whether to include the authentication
398   *                            entry in the response.
399   * @param  includeAuthZEntry  Indicates whether to include the authorization
400   *                            entry in the response.
401   * @param  attributes         The attributes to include in the entries in the
402   *                            response.  It may be empty or {@code null} to
403   *                            request all user attributes.
404   *
405   * @return  An ASN.1 octet string appropriately encoded for use as the control
406   *          value, or {@code null} if no value is needed.
407   */
408  @Nullable()
409  private static ASN1OctetString encodeValue(final boolean includeAuthNEntry,
410                      final boolean includeAuthZEntry,
411                      @Nullable final List<String> attributes)
412  {
413    if (includeAuthNEntry && includeAuthZEntry &&
414        ((attributes == null) || attributes.isEmpty()))
415    {
416      return null;
417    }
418
419    final ArrayList<ASN1Element> elements = new ArrayList<>(3);
420
421    if (! includeAuthNEntry)
422    {
423      elements.add(new ASN1Boolean(TYPE_INCLUDE_AUTHN_ENTRY, false));
424    }
425
426    if (! includeAuthZEntry)
427    {
428      elements.add(new ASN1Boolean(TYPE_INCLUDE_AUTHZ_ENTRY, false));
429    }
430
431    if ((attributes != null) && (! attributes.isEmpty()))
432    {
433      final ArrayList<ASN1Element> attrElements =
434           new ArrayList<>(attributes.size());
435      for (final String s : attributes)
436      {
437        attrElements.add(new ASN1OctetString(s));
438      }
439
440      elements.add(new ASN1Sequence(TYPE_ATTRIBUTES, attrElements));
441    }
442
443    return new ASN1OctetString(new ASN1Sequence(elements).encode());
444  }
445
446
447
448  /**
449   * Indicates whether the entry for the authenticated user should be included
450   * in the response control.
451   *
452   * @return  {@code true} if the entry for the authenticated user should be
453   *          included in the response control, or {@code false} if not.
454   */
455  public boolean includeAuthNEntry()
456  {
457    return includeAuthNEntry;
458  }
459
460
461
462  /**
463   * Indicates whether the entry for the authorized user should be included
464   * in the response control.
465   *
466   * @return  {@code true} if the entry for the authorized user should be
467   *          included in the response control, or {@code false} if not.
468   */
469  public boolean includeAuthZEntry()
470  {
471    return includeAuthZEntry;
472  }
473
474
475
476  /**
477   * Retrieves the attributes that will be requested for the authentication
478   * and/or authorization entries.
479   *
480   * @return  The attributes that will be requested for the authentication
481   *          and/or authorization entries, or an empty list if all user
482   *          attributes should be included.
483   */
484  @NotNull()
485  public List<String> getAttributes()
486  {
487    return attributes;
488  }
489
490
491
492  /**
493   * {@inheritDoc}
494   */
495  @Override()
496  @NotNull()
497  public String getControlName()
498  {
499    return INFO_CONTROL_NAME_GET_AUTHORIZATION_ENTRY_REQUEST.get();
500  }
501
502
503
504  /**
505   * Retrieves a representation of this get authorization entry request control
506   * as a JSON object.  The JSON object uses the following fields:
507   * <UL>
508   *   <LI>
509   *     {@code oid} -- A mandatory string field whose value is the object
510   *     identifier for this control.  For the get authorization entry request
511   *     control, the OID is "1.3.6.1.4.1.30221.2.5.6".
512   *   </LI>
513   *   <LI>
514   *     {@code control-name} -- An optional string field whose value is a
515   *     human-readable name for this control.  This field is only intended for
516   *     descriptive purposes, and when decoding a control, the {@code oid}
517   *     field should be used to identify the type of control.
518   *   </LI>
519   *   <LI>
520   *     {@code criticality} -- A mandatory Boolean field used to indicate
521   *     whether this control is considered critical.
522   *   </LI>
523   *   <LI>
524   *     {@code value-base64} -- An optional string field whose value is a
525   *     base64-encoded representation of the raw value for this get
526   *     authorization entry request control.  Exactly one of the
527   *     {@code value-base64} and {@code value-json} fields must be present.
528   *   </LI>
529   *   <LI>
530   *     {@code value-json} -- An optional JSON object field whose value is a
531   *     user-friendly representation of the value for this get authorization
532   *     entry request control.  Exactly one of the {@code value-base64} and
533   *     {@code value-json} fields must be present, and if the
534   *     {@code value-json} field is used, then it will use the following
535   *     fields:
536   *     <UL>
537   *       <LI>
538   *         {@code include-authentication-entry} -- A mandatory Boolean field
539   *         that indicates whether to include the entry for the authentication
540   *         identity in the response control.
541   *       </LI>
542   *       <LI>
543   *         {@code include-authorization-entry} -- A mandatory Boolean field
544   *         that indicates whether to include the entry for the authorization
545   *         identity in the response control.
546   *       </LI>
547   *       <LI>
548   *         {@code attributes} -- An optional array field whose values are
549   *         strings that represent the names of the attributes that should be
550   *         included in the entries returned in the repsonse control.
551   *       </LI>
552   *     </UL>
553   *   </LI>
554   * </UL>
555   *
556   * @return  A JSON object that contains a representation of this control.
557   */
558  @Override()
559  @NotNull()
560  public JSONObject toJSONControl()
561  {
562    final Map<String,JSONValue> valueFields = new LinkedHashMap<>();
563    valueFields.put(JSON_FIELD_INCLUDE_AUTHENTICATION_ENTRY,
564         new JSONBoolean(includeAuthNEntry));
565    valueFields.put(JSON_FIELD_INCLUDE_AUTHORIZATION_ENTRY,
566         new JSONBoolean(includeAuthZEntry));
567
568    if (! attributes.isEmpty())
569    {
570      final List<JSONValue> attributeValues =
571           new ArrayList<>(attributes.size());
572      for (final String attribute : attributes)
573      {
574        attributeValues.add(new JSONString(attribute));
575      }
576
577      valueFields.put(JSON_FIELD_ATTRIBUTES, new JSONArray(attributeValues));
578    }
579
580
581    return new JSONObject(
582         new JSONField(JSONControlDecodeHelper.JSON_FIELD_OID,
583              GET_AUTHORIZATION_ENTRY_REQUEST_OID),
584         new JSONField(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME,
585              INFO_CONTROL_NAME_GET_AUTHORIZATION_ENTRY_REQUEST.get()),
586         new JSONField(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY,
587              isCritical()),
588         new JSONField(JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON,
589              new JSONObject(valueFields)));
590  }
591
592
593
594  /**
595   * Attempts to decode the provided object as a JSON representation of a get
596   * authorization entry request control.
597   *
598   * @param  controlObject  The JSON object to be decoded.  It must not be
599   *                        {@code null}.
600   * @param  strict         Indicates whether to use strict mode when decoding
601   *                        the provided JSON object.  If this is {@code true},
602   *                        then this method will throw an exception if the
603   *                        provided JSON object contains any unrecognized
604   *                        fields.  If this is {@code false}, then unrecognized
605   *                        fields will be ignored.
606   *
607   * @return  The get authorization entry request control that was decoded from
608   *          the provided JSON object.
609   *
610   * @throws  LDAPException  If the provided JSON object cannot be parsed as a
611   *                         valid get authorization entry request control.
612   */
613  @NotNull()
614  public static GetAuthorizationEntryRequestControl decodeJSONControl(
615              @NotNull final JSONObject controlObject,
616              final boolean strict)
617         throws LDAPException
618  {
619    final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper(
620         controlObject, strict, true, true);
621
622    final ASN1OctetString rawValue = jsonControl.getRawValue();
623    if (rawValue != null)
624    {
625      return new GetAuthorizationEntryRequestControl(new Control(
626           jsonControl.getOID(), jsonControl.getCriticality(), rawValue));
627    }
628
629
630    final JSONObject valueObject = jsonControl.getValueObject();
631
632    final Boolean includeAuthNEntry =
633         valueObject.getFieldAsBoolean(JSON_FIELD_INCLUDE_AUTHENTICATION_ENTRY);
634    if (includeAuthNEntry == null)
635    {
636      throw new LDAPException(ResultCode.DECODING_ERROR,
637           ERR_GET_AUTHORIZATION_ENTRY_REQUEST_JSON_MISSING_FIELD.get(
638                controlObject.toSingleLineString(),
639                JSON_FIELD_INCLUDE_AUTHENTICATION_ENTRY));
640    }
641
642    final Boolean includeAuthZEntry =
643         valueObject.getFieldAsBoolean(JSON_FIELD_INCLUDE_AUTHORIZATION_ENTRY);
644    if (includeAuthZEntry == null)
645    {
646      throw new LDAPException(ResultCode.DECODING_ERROR,
647           ERR_GET_AUTHORIZATION_ENTRY_REQUEST_JSON_MISSING_FIELD.get(
648                controlObject.toSingleLineString(),
649                JSON_FIELD_INCLUDE_AUTHORIZATION_ENTRY));
650    }
651
652
653    final List<String> attributes;
654    final List<JSONValue> attributeValues =
655         valueObject.getFieldAsArray(JSON_FIELD_ATTRIBUTES);
656    if (attributeValues == null)
657    {
658      attributes = null;
659    }
660    else
661    {
662      attributes = new ArrayList<>(attributeValues.size());
663      for (final JSONValue v : attributeValues)
664      {
665        if (v instanceof JSONString)
666        {
667          attributes.add(((JSONString) v).stringValue());
668        }
669        else
670        {
671          throw new LDAPException(ResultCode.DECODING_ERROR,
672               ERR_GET_AUTHORIZATION_ENTRY_REQUEST_JSON_ATTR_NOT_STRING.get(
673                    controlObject.toSingleLineString(),
674                    JSON_FIELD_ATTRIBUTES));
675        }
676      }
677    }
678
679
680    if (strict)
681    {
682      final List<String> unrecognizedFields =
683           JSONControlDecodeHelper.getControlObjectUnexpectedFields(
684                valueObject, JSON_FIELD_INCLUDE_AUTHENTICATION_ENTRY,
685                JSON_FIELD_INCLUDE_AUTHORIZATION_ENTRY, JSON_FIELD_ATTRIBUTES);
686      if (! unrecognizedFields.isEmpty())
687      {
688        throw new LDAPException(ResultCode.DECODING_ERROR,
689             ERR_GET_AUTHORIZATION_ENTRY_REQUEST_JSON_CONTROL_UNRECOGNIZED_FIELD
690                  .get(controlObject.toSingleLineString(),
691                       unrecognizedFields.get(0)));
692      }
693    }
694
695
696    return new GetAuthorizationEntryRequestControl(jsonControl.getCriticality(),
697         includeAuthNEntry, includeAuthZEntry, attributes);
698  }
699
700
701
702  /**
703   * {@inheritDoc}
704   */
705  @Override()
706  public void toString(@NotNull final StringBuilder buffer)
707  {
708    buffer.append("GetAuthorizationEntryRequestControl(isCritical=");
709    buffer.append(isCritical());
710    buffer.append(", includeAuthNEntry=");
711    buffer.append(includeAuthNEntry);
712    buffer.append(", includeAuthZEntry=");
713    buffer.append(includeAuthZEntry);
714    buffer.append(", attributes={");
715
716    final Iterator<String> iterator = attributes.iterator();
717    while (iterator.hasNext())
718    {
719      buffer.append(iterator.next());
720      if (iterator.hasNext())
721      {
722        buffer.append(", ");
723      }
724    }
725
726    buffer.append("})");
727  }
728}