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