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