001/*
002 * Copyright 2007-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2007-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) 2007-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.controls;
037
038
039
040import java.util.List;
041
042import com.unboundid.asn1.ASN1OctetString;
043import com.unboundid.ldap.sdk.BindResult;
044import com.unboundid.ldap.sdk.Control;
045import com.unboundid.ldap.sdk.DecodeableControl;
046import com.unboundid.ldap.sdk.JSONControlDecodeHelper;
047import com.unboundid.ldap.sdk.LDAPException;
048import com.unboundid.ldap.sdk.ResultCode;
049import com.unboundid.util.NotMutable;
050import com.unboundid.util.NotNull;
051import com.unboundid.util.Nullable;
052import com.unboundid.util.ThreadSafety;
053import com.unboundid.util.ThreadSafetyLevel;
054import com.unboundid.util.Validator;
055import com.unboundid.util.json.JSONField;
056import com.unboundid.util.json.JSONObject;
057
058import static com.unboundid.ldap.sdk.controls.ControlMessages.*;
059
060
061
062/**
063 * This class provides an implementation of the authorization identity bind
064 * response control as defined in
065 * <A HREF="http://www.ietf.org/rfc/rfc3829.txt">RFC 3829</A>.  It may be used
066 * to provide the primary authorization identity associated with the client
067 * connection after processing of the associated bind operation has completed.
068 * <BR><BR>
069 * The authorization identity value returned may be empty if the resulting
070 * authorization identity is that of the anonymous user.  Otherwise, it should
071 * be an "authzId" value as described in section 5.2.1.8 of
072 * <A HREF="http://www.ietf.org/rfc/rfc4513.txt">RFC 4513</A>.  That is, it
073 * should be either "dn:" followed by the distinguished name of the target user,
074 * or "u:" followed by the username.
075 * <BR><BR>
076 * Note that the authorization identity response control should only be included
077 * in a bind response message if the corresponding request included the
078 * {@link AuthorizationIdentityRequestControl}, and only if the bind was
079 * successful.
080 */
081@NotMutable()
082@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
083public final class AuthorizationIdentityResponseControl
084       extends Control
085       implements DecodeableControl
086{
087  /**
088   * The OID (2.16.840.1.113730.3.4.15) for the authorization identity response
089   * control.
090   */
091  @NotNull public static final String AUTHORIZATION_IDENTITY_RESPONSE_OID =
092       "2.16.840.1.113730.3.4.15";
093
094
095
096  /**
097   * The name of the field used to represent the authorization ID in the JSON
098   * representation of this control.
099   */
100  @NotNull private static final String JSON_FIELD_AUTHORIZATION_ID =
101       "authorization-id";
102
103
104
105  /**
106   * The serial version UID for this serializable class.
107   */
108  private static final long serialVersionUID = -6315724175438820336L;
109
110
111
112  // The authorization ID string returned by the server.
113  @NotNull private final String authorizationID;
114
115
116
117  /**
118   * Creates a new empty control instance that is intended to be used only for
119   * decoding controls via the {@code DecodeableControl} interface.
120   */
121  AuthorizationIdentityResponseControl()
122  {
123    authorizationID = null;
124  }
125
126
127
128  /**
129   * Creates a new authorization identity response control with the provided
130   * authorization ID.
131   *
132   * @param  authorizationID  The authorization identity associated with the
133   *                          client connection.  It must not be {@code null},
134   *                          although it may be a zero-length string to
135   *                          indicate that the authorization identity is the
136   *                          anonymous user.
137   */
138  public AuthorizationIdentityResponseControl(
139              @NotNull final String authorizationID)
140  {
141    super(AUTHORIZATION_IDENTITY_RESPONSE_OID, false,
142          new ASN1OctetString(authorizationID));
143
144    Validator.ensureNotNull(authorizationID);
145
146    this.authorizationID = authorizationID;
147  }
148
149
150
151  /**
152   * Creates a new authorization identity response control with the provided
153   * information.
154   *
155   * @param  oid         The OID for the control.
156   * @param  isCritical  Indicates whether the control should be marked
157   *                     critical.
158   * @param  value       The encoded value for the control.  This may be
159   *                     {@code null} if no value was provided.
160   *
161   * @throws  LDAPException  If the provided control cannot be decoded as an
162   *                         authorization identity response control.
163   */
164  public AuthorizationIdentityResponseControl(@NotNull final String oid,
165              final boolean isCritical,
166              @Nullable final ASN1OctetString value)
167         throws LDAPException
168  {
169    super(oid, isCritical, value);
170
171    if (value == null)
172    {
173      throw new LDAPException(ResultCode.DECODING_ERROR,
174                              ERR_AUTHZID_RESPONSE_NO_VALUE.get());
175    }
176    else
177    {
178      authorizationID = value.stringValue();
179    }
180  }
181
182
183
184  /**
185   * {@inheritDoc}
186   */
187  @Override()
188  @NotNull()
189  public AuthorizationIdentityResponseControl
190              decodeControl(@NotNull final String oid, final boolean isCritical,
191                            @Nullable final ASN1OctetString value)
192         throws LDAPException
193  {
194    return new AuthorizationIdentityResponseControl(oid, isCritical, value);
195  }
196
197
198
199  /**
200   * Extracts an authorization identity response control from the provided
201   * result.
202   *
203   * @param  result  The result from which to retrieve the authorization
204   *                 identity response control.
205   *
206   * @return  The authorization identity response control contained in the
207   *          provided result, or {@code null} if the result did not contain an
208   *          authorization identity response control.
209   *
210   * @throws  LDAPException  If a problem is encountered while attempting to
211   *                         decode the authorization identity response control
212   *                         contained in the provided result.
213   */
214  @Nullable()
215  public static AuthorizationIdentityResponseControl get(
216                     @NotNull final BindResult result)
217         throws LDAPException
218  {
219    final Control c =
220         result.getResponseControl(AUTHORIZATION_IDENTITY_RESPONSE_OID);
221    if (c == null)
222    {
223      return null;
224    }
225
226    if (c instanceof AuthorizationIdentityResponseControl)
227    {
228      return (AuthorizationIdentityResponseControl) c;
229    }
230    else
231    {
232      return new AuthorizationIdentityResponseControl(c.getOID(),
233           c.isCritical(), c.getValue());
234    }
235  }
236
237
238
239  /**
240   * Retrieves the authorization ID string for this authorization identity
241   * response control.  It may be a zero-length string if the associated
242   * authorization identity is that of the anonymous user.
243   *
244   * @return  The authorization ID string for this authorization identity
245   *          response control.
246   */
247  @NotNull()
248  public String getAuthorizationID()
249  {
250    return authorizationID;
251  }
252
253
254
255  /**
256   * {@inheritDoc}
257   */
258  @Override()
259  @NotNull()
260  public String getControlName()
261  {
262    return INFO_CONTROL_NAME_AUTHZID_RESPONSE.get();
263  }
264
265
266
267  /**
268   * Retrieves a representation of this authorization identity response control
269   * as a JSON object.  The JSON object uses the following fields:
270   * <UL>
271   *   <LI>
272   *     {@code oid} -- A mandatory string field whose value is the object
273   *     identifier for this control.  For the authorization identity response
274   *     control, the OID is "2.16.840.1.113730.3.4.15".
275   *   </LI>
276   *   <LI>
277   *     {@code control-name} -- An optional string field whose value is a
278   *     human-readable name for this control.  This field is only intended for
279   *     descriptive purposes, and when decoding a control, the {@code oid}
280   *     field should be used to identify the type of control.
281   *   </LI>
282   *   <LI>
283   *     {@code criticality} -- A mandatory Boolean field used to indicate
284   *     whether this control is considered critical.
285   *   </LI>
286   *   <LI>
287   *     {@code value-base64} -- An optional string field whose value is a
288   *     base64-encoded representation of the raw value for this authorization
289   *     identity response control.  Exactly one of the {@code value-base64} and
290   *     {@code value-json} fields must be present.
291   *   </LI>
292   *   <LI>
293   *     {@code value-json} -- An optional JSON object field whose value is a
294   *     user-friendly representation of the value for this authorization
295   *     identity response control.  Exactly one of the {@code value-base64} and
296   *     {@code value-json} fields must be present, and if the
297   *     {@code value-json} field is used, then it will use the following
298   *     fields:
299   *     <UL>
300   *       <LI>
301   *         {@code authorization-id} -- A string field whose value is the
302   *         authorization identity assigned during the bind operation.
303   *       </LI>
304   *     </UL>
305   *   </LI>
306   * </UL>
307   *
308   * @return  A JSON object that contains a representation of this control.
309   */
310  @Override()
311  @NotNull()
312  public JSONObject toJSONControl()
313  {
314    return new JSONObject(
315         new JSONField(JSONControlDecodeHelper.JSON_FIELD_OID,
316              AUTHORIZATION_IDENTITY_RESPONSE_OID),
317         new JSONField(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME,
318              INFO_CONTROL_NAME_AUTHZID_RESPONSE.get()),
319         new JSONField(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY,
320              isCritical()),
321         new JSONField(JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON,
322              new JSONObject(
323                   new JSONField(JSON_FIELD_AUTHORIZATION_ID,
324                        authorizationID))));
325  }
326
327
328
329  /**
330   * Attempts to decode the provided object as a JSON representation of an
331   * authorization identity response control.
332   *
333   * @param  controlObject  The JSON object to be decoded.  It must not be
334   *                        {@code null}.
335   * @param  strict         Indicates whether to use strict mode when decoding
336   *                        the provided JSON object.  If this is {@code true},
337   *                        then this method will throw an exception if the
338   *                        provided JSON object contains any unrecognized
339   *                        fields.  If this is {@code false}, then unrecognized
340   *                        fields will be ignored.
341   *
342   * @return  The authorization identity response control that was decoded from
343   *          the provided JSON object.
344   *
345   * @throws  LDAPException  If the provided JSON object cannot be parsed as a
346   *                         valid authorization identity response control.
347   */
348  @NotNull()
349  public static AuthorizationIdentityResponseControl decodeJSONControl(
350              @NotNull final JSONObject controlObject,
351              final boolean strict)
352         throws LDAPException
353  {
354    final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper(
355         controlObject, strict, true, true);
356
357    final ASN1OctetString rawValue = jsonControl.getRawValue();
358    if (rawValue != null)
359    {
360      return new AuthorizationIdentityResponseControl(jsonControl.getOID(),
361           jsonControl.getCriticality(), rawValue);
362    }
363
364
365    final JSONObject valueObject = jsonControl.getValueObject();
366
367    final String authzID =
368         valueObject.getFieldAsString(JSON_FIELD_AUTHORIZATION_ID);
369    if (authzID == null)
370    {
371      throw new LDAPException(ResultCode.DECODING_ERROR,
372           ERR_AUTHZID_RESPONSE_JSON_MISSING_AUTHZ_ID.get(
373                valueObject.toSingleLineString(),
374                JSON_FIELD_AUTHORIZATION_ID));
375    }
376
377
378    if (strict)
379    {
380      final List<String> unrecognizedFields =
381           JSONControlDecodeHelper.getControlObjectUnexpectedFields(
382                valueObject, JSON_FIELD_AUTHORIZATION_ID);
383      if (! unrecognizedFields.isEmpty())
384      {
385        throw new LDAPException(ResultCode.DECODING_ERROR,
386             ERR_AUTHZID_RESPONSE_JSON_CONTROL_UNRECOGNIZED_FIELD.get(
387                  controlObject.toSingleLineString(),
388                  unrecognizedFields.get(0)));
389      }
390    }
391
392
393    return new AuthorizationIdentityResponseControl(authzID);
394  }
395
396
397
398  /**
399   * {@inheritDoc}
400   */
401  @Override()
402  public void toString(@NotNull final StringBuilder buffer)
403  {
404    buffer.append("AuthorizationIdentityResponseControl(authorizationID='");
405    buffer.append(authorizationID);
406    buffer.append("', isCritical=");
407    buffer.append(isCritical());
408    buffer.append(')');
409  }
410}