001/*
002 * Copyright 2015-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2015-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) 2015-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.extensions;
037
038
039
040import java.util.ArrayList;
041
042import com.unboundid.asn1.ASN1Element;
043import com.unboundid.asn1.ASN1OctetString;
044import com.unboundid.asn1.ASN1Sequence;
045import com.unboundid.ldap.sdk.Control;
046import com.unboundid.ldap.sdk.ExtendedResult;
047import com.unboundid.ldap.sdk.LDAPException;
048import com.unboundid.ldap.sdk.ResultCode;
049import com.unboundid.util.Debug;
050import com.unboundid.util.NotMutable;
051import com.unboundid.util.NotNull;
052import com.unboundid.util.Nullable;
053import com.unboundid.util.StaticUtils;
054import com.unboundid.util.ThreadSafety;
055import com.unboundid.util.ThreadSafetyLevel;
056import com.unboundid.util.Validator;
057
058import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
059
060
061
062/**
063 * This class provides an implementation of an extended result that may be used
064 * to provide information about the result of processing for a deliver password
065 * reset token extended request.  If the token was delivered successfully, then
066 * this result will include information about the mechanism through which the
067 * token was delivered.
068 * <BR>
069 * <BLOCKQUOTE>
070 *   <B>NOTE:</B>  This class, and other classes within the
071 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
072 *   supported for use against Ping Identity, UnboundID, and
073 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
074 *   for proprietary functionality or for external specifications that are not
075 *   considered stable or mature enough to be guaranteed to work in an
076 *   interoperable way with other types of LDAP servers.
077 * </BLOCKQUOTE>
078 * <BR>
079 * If the request was processed successfully, then the extended result will have
080 * an OID of 1.3.6.1.4.1.30221.2.6.46 and a value with the following encoding:
081 * <BR><BR>
082 * <PRE>
083 *   DeliverPasswordResetTokenResult ::= SEQUENCE {
084 *        deliveryMechanism     OCTET STRING,
085 *        recipientID           [0] OCTET STRING OPTIONAL,
086 *        message               [1] OCTET STRING OPTIONAL,
087 *        ... }
088 * </PRE>
089 *
090 * @see  DeliverPasswordResetTokenExtendedRequest
091 */
092@NotMutable()
093@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
094public final class DeliverPasswordResetTokenExtendedResult
095       extends ExtendedResult
096{
097  /**
098   * The OID (1.3.6.1.4.1.30221.2.6.46) for the deliver password reset token
099   * extended result.
100   */
101  @NotNull public static final String DELIVER_PW_RESET_TOKEN_RESULT_OID =
102       "1.3.6.1.4.1.30221.2.6.46";
103
104
105
106  /**
107   * The BER type for the recipient ID element of the value sequence.
108   */
109  private static final byte RECIPIENT_ID_BER_TYPE = (byte) 0x80;
110
111
112
113  /**
114   * The BER type for the message element of the value sequence.
115   */
116  private static final byte DELIVERY_MESSAGE_BER_TYPE = (byte) 0x81;
117
118
119
120  /**
121   * The serial version UID for this serializable class.
122   */
123  private static final long serialVersionUID = 576599499447071902L;
124
125
126
127  // The name of the mechanism by which the password reset token was delivered.
128  @Nullable private final String deliveryMechanism;
129
130  // An message providing additional information about the delivery of the
131  // password reset token.
132  @Nullable private final String deliveryMessage;
133
134  // An identifier for the recipient of the password reset token.
135  @Nullable private final String recipientID;
136
137
138
139  /**
140   * Creates a new deliver password reset token extended result with the
141   * provided information.
142   *
143   * @param  messageID          The message ID for the LDAP message that is
144   *                            associated with this LDAP result.
145   * @param  resultCode         The result code from the response.  It must not
146   *                            be {@code null}.
147   * @param  diagnosticMessage  The diagnostic message from the response, if
148   *                            available.
149   * @param  matchedDN          The matched DN from the response, if available.
150   * @param  referralURLs       The set of referral URLs from the response, if
151   *                            available.
152   * @param  deliveryMechanism  The name of the mechanism by which the password
153   *                            reset token was delivered, if available.  This
154   *                            should be non-{@code null} for a success result.
155   * @param  recipientID        An identifier for the user to whom the password
156   *                            reset token was delivered.  It may be
157   *                            {@code null} if no token was delivered or there
158   *                            is no appropriate identifier, but if a value is
159   *                            provided then it should appropriate for the
160   *                            delivery mechanism (e.g., the user's e-mail
161   *                            address if delivered via e-mail, a phone number
162   *                            if delivered via SMS or voice call, etc.).
163   * @param  deliveryMessage    An optional message providing additional
164   *                            information about the password reset token
165   *                            delivery, if available.  If this is
166   *                            non-{@code null}, then the delivery mechanism
167   *                            must also be non-null.
168   * @param  responseControls   The set of controls for the response, if
169   *                            available.
170   */
171  public DeliverPasswordResetTokenExtendedResult(final int messageID,
172              @NotNull final ResultCode resultCode,
173              @Nullable final String diagnosticMessage,
174              @Nullable final String matchedDN,
175              @Nullable final String[] referralURLs,
176              @Nullable final String deliveryMechanism,
177              @Nullable final String recipientID,
178              @Nullable final String deliveryMessage,
179              @Nullable final Control... responseControls)
180  {
181    super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
182         ((deliveryMechanism == null)
183              ? null : DELIVER_PW_RESET_TOKEN_RESULT_OID),
184         encodeValue(deliveryMechanism, recipientID, deliveryMessage),
185         responseControls);
186
187    this.deliveryMechanism = deliveryMechanism;
188    this.recipientID       = recipientID;
189    this.deliveryMessage   = deliveryMessage;
190  }
191
192
193
194  /**
195   * Creates a new deliver password reset token result from the provided generic
196   * extended result.
197   *
198   * @param  result  The generic extended result to be parsed as a deliver
199   *                 password reset token result.
200   *
201   * @throws LDAPException  If the provided extended result cannot be parsed as
202   *                         a deliver password reset token result.
203   */
204  public DeliverPasswordResetTokenExtendedResult(
205              @NotNull final ExtendedResult result)
206       throws LDAPException
207  {
208    super(result);
209
210    final ASN1OctetString value = result.getValue();
211    if (value == null)
212    {
213      deliveryMechanism = null;
214      recipientID       = null;
215      deliveryMessage   = null;
216      return;
217    }
218
219    try
220    {
221      final ASN1Element[] elements =
222           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
223      deliveryMechanism =
224           ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
225
226      String id = null;
227      String msg = null;
228      for (int i=1; i < elements.length; i++)
229      {
230        switch (elements[i].getType())
231        {
232          case RECIPIENT_ID_BER_TYPE:
233            id = ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
234            break;
235
236          case DELIVERY_MESSAGE_BER_TYPE:
237            msg = ASN1OctetString.decodeAsOctetString(
238                 elements[i]).stringValue();
239            break;
240
241          default:
242            throw new LDAPException(ResultCode.DECODING_ERROR,
243                 ERR_DELIVER_PW_RESET_TOKEN_RESULT_UNEXPECTED_TYPE.get(
244                      StaticUtils.toHex(elements[i].getType())));
245        }
246      }
247
248      recipientID = id;
249      deliveryMessage = msg;
250    }
251    catch (final LDAPException le)
252    {
253      Debug.debugException(le);
254      throw le;
255    }
256    catch (final Exception e)
257    {
258      Debug.debugException(e);
259      throw new LDAPException(ResultCode.DECODING_ERROR,
260           ERR_DELIVER_PW_RESET_TOKEN_RESULT_ERROR_DECODING_VALUE.get(
261                StaticUtils.getExceptionMessage(e)),
262           e);
263    }
264  }
265
266
267
268  /**
269   * Encodes the provided information into an ASN.1 octet string suitable for
270   * use as the value of this extended result.
271   *
272   * @param  deliveryMechanism  The name of the mechanism by which the password
273   *                            reset token was delivered, if available.  This
274   *                            should be non-{@code null} for a success result.
275   * @param  recipientID        An identifier for the user to whom the password
276   *                            reset token was delivered.  It may be
277   *                            {@code null} if no token was delivered or there
278   *                            is no appropriate identifier, but if a value is
279   *                            provided then it should appropriate for the
280   *                            delivery mechanism (e.g., the user's e-mail
281   *                            address if delivered via e-mail, a phone number
282   *                            if delivered via SMS or voice call, etc.).
283   * @param  deliveryMessage    An optional message providing additional
284   *                            information about the password reset token
285   *                            delivery, if available.  If this is
286   *                            non-{@code null}, then the delivery mechanism
287   *                            must also be non-null.
288   *
289   * @return  An ASN.1 octet string containing the encoded value, or
290   *          {@code null} if the extended result should not have a value.
291   */
292  @Nullable()
293  private static ASN1OctetString encodeValue(
294               @Nullable final String deliveryMechanism,
295               @Nullable final String recipientID,
296               @Nullable final String deliveryMessage)
297  {
298    if (deliveryMechanism == null)
299    {
300      Validator.ensureTrue((recipientID == null),
301           "The delivery mechanism must be non-null if the recipient ID " +
302                "is non-null.");
303      Validator.ensureTrue((deliveryMessage == null),
304           "The delivery mechanism must be non-null if the delivery message " +
305                "is non-null.");
306      return null;
307    }
308
309    final ArrayList<ASN1Element> elements = new ArrayList<>(3);
310    elements.add(new ASN1OctetString(deliveryMechanism));
311
312    if (recipientID != null)
313    {
314      elements.add(new ASN1OctetString(RECIPIENT_ID_BER_TYPE, recipientID));
315    }
316
317    if (deliveryMessage != null)
318    {
319      elements.add(new ASN1OctetString(DELIVERY_MESSAGE_BER_TYPE,
320           deliveryMessage));
321    }
322
323    return new ASN1OctetString(new ASN1Sequence(elements).encode());
324  }
325
326
327
328  /**
329   * Retrieves the name of the mechanism by which the password reset token was
330   * delivered to the user, if available.
331   *
332   * @return  The name of the mechanism by which the password reset token was
333   *          delivered to the user, or {@code null} if this is not available.
334   */
335  @Nullable()
336  public String getDeliveryMechanism()
337  {
338    return deliveryMechanism;
339  }
340
341
342
343  /**
344   * Retrieves an identifier for the user to whom the password reset token was
345   * delivered, if available.  If a recipient ID is provided, then it should be
346   * in a form appropriate to the delivery mechanism (e.g., an e-mail address
347   * if the token was delivered by e-mail, a phone number if it was delivered
348   * by SMS or a voice call, etc.).
349   *
350   * @return  An identifier for the user to whom the password reset token was
351   *          delivered, or {@code null} if this is not available.
352   */
353  @Nullable()
354  public String getRecipientID()
355  {
356    return recipientID;
357  }
358
359
360
361  /**
362   * Retrieves a message providing additional information about the password
363   * reset token delivery, if available.
364   *
365   * @return  A message providing additional information about the password
366   *          reset token delivery, or {@code null} if this is not available.
367   */
368  @Nullable()
369  public String getDeliveryMessage()
370  {
371    return deliveryMessage;
372  }
373
374
375
376  /**
377   * {@inheritDoc}
378   */
379  @Override()
380  @Nullable()
381  public String getExtendedResultName()
382  {
383    return INFO_EXTENDED_RESULT_NAME_DELIVER_PW_RESET_TOKEN.get();
384  }
385
386
387
388  /**
389   * Appends a string representation of this extended result to the provided
390   * buffer.
391   *
392   * @param  buffer  The buffer to which a string representation of this
393   *                 extended result will be appended.
394   */
395  @Override()
396  public void toString(@NotNull final StringBuilder buffer)
397  {
398    buffer.append("DeliverPasswordResetTokenExtendedResult(resultCode=");
399    buffer.append(getResultCode());
400
401    final int messageID = getMessageID();
402    if (messageID >= 0)
403    {
404      buffer.append(", messageID=");
405      buffer.append(messageID);
406    }
407
408    if (deliveryMechanism != null)
409    {
410      buffer.append(", deliveryMechanism='");
411      buffer.append(deliveryMechanism);
412      buffer.append('\'');
413    }
414
415    if (recipientID != null)
416    {
417      buffer.append(", recipientID='");
418      buffer.append(recipientID);
419      buffer.append('\'');
420    }
421
422    if (deliveryMessage != null)
423    {
424      buffer.append(", deliveryMessage='");
425      buffer.append(deliveryMessage);
426      buffer.append('\'');
427    }
428
429    final String diagnosticMessage = getDiagnosticMessage();
430    if (diagnosticMessage != null)
431    {
432      buffer.append(", diagnosticMessage='");
433      buffer.append(diagnosticMessage);
434      buffer.append('\'');
435    }
436
437    final String matchedDN = getMatchedDN();
438    if (matchedDN != null)
439    {
440      buffer.append(", matchedDN='");
441      buffer.append(matchedDN);
442      buffer.append('\'');
443    }
444
445    final String[] referralURLs = getReferralURLs();
446    if (referralURLs.length > 0)
447    {
448      buffer.append(", referralURLs={");
449      for (int i=0; i < referralURLs.length; i++)
450      {
451        if (i > 0)
452        {
453          buffer.append(", ");
454        }
455
456        buffer.append('\'');
457        buffer.append(referralURLs[i]);
458        buffer.append('\'');
459      }
460      buffer.append('}');
461    }
462
463    final Control[] responseControls = getResponseControls();
464    if (responseControls.length > 0)
465    {
466      buffer.append(", responseControls={");
467      for (int i=0; i < responseControls.length; i++)
468      {
469        if (i > 0)
470        {
471          buffer.append(", ");
472        }
473
474        buffer.append(responseControls[i]);
475      }
476      buffer.append('}');
477    }
478
479    buffer.append(')');
480  }
481}