001/*
002 * Copyright 2013-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2015-2018 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 one-time
048 * password extended request.  If the one-time password was delivered
049 * successfully, then this result will include information about the mechanism
050 * through which that message 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.25 and a value with the following encoding:
064 * <BR><BR>
065 * <PRE>
066 *   DeliverOTPResult ::= SEQUENCE {
067 *        deliveryMechanism     [0] OCTET STRING,
068 *        recipientDN           [1] LDAPDN,
069 *        recipientID           [2] OCTET STRING OPTIONAL,
070 *        message               [3] OCTET STRING OPTIONAL,
071 *        ... }
072 * </PRE>
073 *
074 * @see  com.unboundid.ldap.sdk.unboundidds.UnboundIDDeliveredOTPBindRequest
075 * @see  DeliverOneTimePasswordExtendedRequest
076 */
077@NotMutable()
078@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
079public final class DeliverOneTimePasswordExtendedResult
080       extends ExtendedResult
081{
082  /**
083   * The OID (1.3.6.1.4.1.30221.2.6.25) for the deliver one-time password
084   * extended result.
085   */
086  public static final String DELIVER_OTP_RESULT_OID =
087       "1.3.6.1.4.1.30221.2.6.25";
088
089
090
091  /**
092   * The BER type for the delivery mechanism element.
093   */
094  private static final byte TYPE_MECH = (byte) 0x80;
095
096
097
098  /**
099   * The BER type for the recipient DN element.
100   */
101  private static final byte TYPE_RECIPIENT_DN = (byte) 0x81;
102
103
104
105  /**
106   * The BER type for the recipient ID element.
107   */
108  private static final byte TYPE_RECIPIENT_ID = (byte) 0x82;
109
110
111
112  /**
113   * The BER type for the delivery message element.
114   */
115  private static final byte TYPE_MESSAGE = (byte) 0x83;
116
117
118
119  /**
120   * The serial version UID for this serializable class.
121   */
122  private static final long serialVersionUID = 5077693879184160485L;
123
124
125
126  // The name of the mechanism by which the one-time password was delivered.
127  private final String deliveryMechanism;
128
129  // An message providing additional information about the delivery of the
130  // one-time password.
131  private final String deliveryMessage;
132
133  // An the DN of the user to whom the one-time password was sent.
134  private final String recipientDN;
135
136  // An identifier for the recipient of the one-time password.
137  private final String recipientID;
138
139
140
141  /**
142   * Creates a new deliver one-time password extended result from the provided
143   * generic extended result.
144   *
145   * @param  extendedResult  The generic extended result to be parsed as a
146   *                         deliver one-time password result.
147   *
148   * @throws LDAPException  If the provided extended result cannot be parsed as
149   *                         a deliver one-time password result.
150   */
151  public DeliverOneTimePasswordExtendedResult(
152       final ExtendedResult extendedResult)
153       throws LDAPException
154  {
155    super(extendedResult);
156
157    final ASN1OctetString value = extendedResult.getValue();
158    if (value == null)
159    {
160      deliveryMechanism = null;
161      recipientDN = null;
162      recipientID = null;
163      deliveryMessage = null;
164      return;
165    }
166
167    String mech = null;
168    String dn = null;
169    String id = null;
170    String message = null;
171    try
172    {
173      for (final ASN1Element e :
174           ASN1Sequence.decodeAsSequence(value.getValue()).elements())
175      {
176        switch (e.getType())
177        {
178          case TYPE_MECH:
179            mech = ASN1OctetString.decodeAsOctetString(e).stringValue();
180            break;
181          case TYPE_RECIPIENT_DN:
182            dn = ASN1OctetString.decodeAsOctetString(e).stringValue();
183            break;
184          case TYPE_RECIPIENT_ID:
185            id = ASN1OctetString.decodeAsOctetString(e).stringValue();
186            break;
187          case TYPE_MESSAGE:
188            message = ASN1OctetString.decodeAsOctetString(e).stringValue();
189            break;
190          default:
191            throw new LDAPException(ResultCode.DECODING_ERROR,
192                 ERR_DELIVER_OTP_RES_UNEXPECTED_ELEMENT_TYPE.get(
193                      StaticUtils.toHex(e.getType())));
194        }
195      }
196    }
197    catch (final LDAPException le)
198    {
199      Debug.debugException(le);
200      throw le;
201    }
202    catch (final Exception e)
203    {
204      Debug.debugException(e);
205      throw new LDAPException(ResultCode.DECODING_ERROR,
206           ERR_DELIVER_OTP_RES_ERROR_PARSING_VALUE.get(
207                StaticUtils.getExceptionMessage(e)),
208           e);
209    }
210
211
212    if (mech == null)
213    {
214      throw new LDAPException(ResultCode.DECODING_ERROR,
215           ERR_DELIVER_OTP_RES_NO_MECH.get());
216    }
217    else
218    {
219      deliveryMechanism = mech;
220    }
221
222    if (dn == null)
223    {
224      throw new LDAPException(ResultCode.DECODING_ERROR,
225           ERR_DELIVER_OTP_RES_NO_RECIPIENT_DN.get());
226    }
227    else
228    {
229      recipientDN = dn;
230    }
231
232    recipientID = id;
233    deliveryMessage = message;
234  }
235
236
237
238  /**
239   * Creates a new deliver one-time password extended result with the provided
240   * information.
241   *
242   * @param  messageID          The message ID for the LDAP message that is
243   *                            associated with this LDAP result.
244   * @param  resultCode         The result code from the response.
245   * @param  diagnosticMessage  The diagnostic message from the response, if
246   *                            available.
247   * @param  matchedDN          The matched DN from the response, if available.
248   * @param  referralURLs       The set of referral URLs from the response, if
249   *                            available.
250   * @param  deliveryMechanism  The name of the mechanism by which the one-time
251   *                            password was delivered, if available.  This
252   *                            should be non-{@code null} for a success result.
253   * @param  recipientDN        The DN of the user to whom the one-time password
254   *                            was sent.  This should be non-{@code null} for a
255   *                            success result.
256   * @param  recipientID        An identifier for the user to whom the one-time
257   *                            password was delivered.  It may be {@code null}
258   *                            if no password was delivered or there is no
259   *                            appropriate identifier, but if a value is
260   *                            provided then it should appropriate for the
261   *                            delivery mechanism (e.g., the user's e-mail
262   *                            address if delivered via e-mail, a phone number
263   *                            if delivered via SMS or voice call, etc.).
264   * @param  deliveryMessage    A message providing additional information about
265   *                            the one-time password delivery, if available.
266   *                            If this is non-{@code null}, then the delivery
267   *                            mechanism must also be non-null.
268   * @param  responseControls   The set of controls from the response, if
269   *                            available.
270   */
271  public DeliverOneTimePasswordExtendedResult(final int messageID,
272              final ResultCode resultCode, final String diagnosticMessage,
273              final String matchedDN, final String[] referralURLs,
274              final String deliveryMechanism, final String recipientDN,
275              final String recipientID, final String deliveryMessage,
276              final Control... responseControls)
277  {
278    super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
279         ((deliveryMechanism == null) ? null : DELIVER_OTP_RESULT_OID),
280         encodeValue(deliveryMechanism, recipientDN, recipientID,
281              deliveryMessage),
282         responseControls);
283
284    this.deliveryMechanism = deliveryMechanism;
285    this.recipientDN       = recipientDN;
286    this.recipientID       = recipientID;
287    this.deliveryMessage   = deliveryMessage;
288  }
289
290
291
292  /**
293   * Encodes the provided information into an ASN.1 octet string suitable for
294   * use as the value of this extended result.
295   *
296   * @param  deliveryMechanism  The name of the mechanism by which the one-time
297   *                            password was delivered, if available.  This
298   *                            should be non-{@code null} for a success result.
299   * @param  recipientDN        The DN of the user to whom the one-time password
300   *                            was sent.  This should be non-{@code null} for a
301   *                            success result.
302   * @param  recipientID        An identifier for the user to whom the one-time
303   *                            password was delivered.  It may be {@code null}
304   *                            if no password was delivered or there is no
305   *                            appropriate identifier, but if a value is
306   *                            provided then it should appropriate for the
307   *                            delivery mechanism (e.g., the user's e-mail
308   *                            address if delivered via e-mail, a phone number
309   *                            if delivered via SMS or voice call, etc.).
310   * @param  deliveryMessage    A message providing additional information about
311   *                            the one-time password delivery, if available.
312   *                            If this is non-{@code null}, then the delivery
313   *                            mechanism must also be non-null.
314   *
315   * @return  An ASN.1 octet string containing the encoded value, or
316   *          {@code null} if the extended result should not have a value.
317   */
318  private static ASN1OctetString encodeValue(final String deliveryMechanism,
319                                             final String recipientDN,
320                                             final String recipientID,
321                                             final String deliveryMessage)
322  {
323    if (deliveryMechanism == null)
324    {
325      Validator.ensureTrue((recipientID == null),
326           "The delivery mechanism must be non-null if the recipient ID " +
327                "is non-null.");
328      Validator.ensureTrue((deliveryMessage == null),
329           "The delivery mechanism must be non-null if the delivery message " +
330                "is non-null.");
331      return null;
332    }
333
334    Validator.ensureTrue((recipientDN != null),
335         "If a delivery mechanism is provided, then a recipient DN must also " +
336              "be provided.");
337
338    final ArrayList<ASN1Element> elements = new ArrayList<>(4);
339    elements.add(new ASN1OctetString(TYPE_MECH, deliveryMechanism));
340    elements.add(new ASN1OctetString(TYPE_RECIPIENT_DN, recipientDN));
341
342    if (recipientID != null)
343    {
344      elements.add(new ASN1OctetString(TYPE_RECIPIENT_ID, recipientID));
345    }
346
347    if (deliveryMessage != null)
348    {
349      elements.add(new ASN1OctetString(TYPE_MESSAGE, deliveryMessage));
350    }
351
352    return new ASN1OctetString(new ASN1Sequence(elements).encode());
353  }
354
355
356
357  /**
358   * Retrieves the name of the mechanism by which the one-time password was
359   * delivered to the end user, if available.
360   *
361   * @return  The name of the mechanism by which the one-time password was
362   *          delivered to the end user, or {@code null} if this is not
363   *          available.
364   */
365  public String getDeliveryMechanism()
366  {
367    return deliveryMechanism;
368  }
369
370
371
372  /**
373   * Retrieves the DN of the user to whom the one-time password was delivered,
374   * if available.
375   *
376   * @return  The DN of the user to whom the one-time password was delivered, or
377   *          {@code null} if this is not available.
378   */
379  public String getRecipientDN()
380  {
381    return recipientDN;
382  }
383
384
385
386  /**
387   * Retrieves an identifier for the user to whom the one-time password was
388   * delivered, if available.  If a recipient ID is provided, then it should be
389   * in a form appropriate to the delivery mechanism (e.g., an e-mail address
390   * if the password was delivered by e-mail, a phone number if it was delivered
391   * by SMS or a voice call, etc.).
392   *
393   * @return  An identifier for the user to whom the one-time password was
394   *          delivered, or {@code null} if this is not available.
395   */
396  public String getRecipientID()
397  {
398    return recipientID;
399  }
400
401
402
403  /**
404   * Retrieves a message providing additional information about the one-time
405   * password delivery, if available.
406   *
407   * @return  A message providing additional information about the one-time
408   *          password delivery, or {@code null} if this is not available.
409   */
410  public String getDeliveryMessage()
411  {
412    return deliveryMessage;
413  }
414
415
416
417  /**
418   * {@inheritDoc}
419   */
420  @Override()
421  public String getExtendedResultName()
422  {
423    return INFO_DELIVER_OTP_RES_NAME.get();
424  }
425
426
427
428  /**
429   * Appends a string representation of this extended result to the provided
430   * buffer.
431   *
432   * @param  buffer  The buffer to which a string representation of this
433   *                 extended result will be appended.
434   */
435  @Override()
436  public void toString(final StringBuilder buffer)
437  {
438    buffer.append("DeliverOneTimePasswordExtendedResult(resultCode=");
439    buffer.append(getResultCode());
440
441    final int messageID = getMessageID();
442    if (messageID >= 0)
443    {
444      buffer.append(", messageID=");
445      buffer.append(messageID);
446    }
447
448    if (deliveryMechanism != null)
449    {
450      buffer.append(", deliveryMechanism='");
451      buffer.append(deliveryMechanism);
452      buffer.append('\'');
453    }
454
455    if (recipientDN != null)
456    {
457      buffer.append(", recipientDN='");
458      buffer.append(recipientDN);
459      buffer.append('\'');
460    }
461
462    if (recipientID != null)
463    {
464      buffer.append(", recipientID='");
465      buffer.append(recipientID);
466      buffer.append('\'');
467    }
468
469    if (deliveryMessage != null)
470    {
471      buffer.append(", deliveryMessage='");
472      buffer.append(deliveryMessage);
473      buffer.append('\'');
474    }
475
476    final String diagnosticMessage = getDiagnosticMessage();
477    if (diagnosticMessage != null)
478    {
479      buffer.append(", diagnosticMessage='");
480      buffer.append(diagnosticMessage);
481      buffer.append('\'');
482    }
483
484    final String matchedDN = getMatchedDN();
485    if (matchedDN != null)
486    {
487      buffer.append(", matchedDN='");
488      buffer.append(matchedDN);
489      buffer.append('\'');
490    }
491
492    final String[] referralURLs = getReferralURLs();
493    if (referralURLs.length > 0)
494    {
495      buffer.append(", referralURLs={");
496      for (int i=0; i < referralURLs.length; i++)
497      {
498        if (i > 0)
499        {
500          buffer.append(", ");
501        }
502
503        buffer.append('\'');
504        buffer.append(referralURLs[i]);
505        buffer.append('\'');
506      }
507      buffer.append('}');
508    }
509
510    final Control[] responseControls = getResponseControls();
511    if (responseControls.length > 0)
512    {
513      buffer.append(", responseControls={");
514      for (int i=0; i < responseControls.length; i++)
515      {
516        if (i > 0)
517        {
518          buffer.append(", ");
519        }
520
521        buffer.append(responseControls[i]);
522      }
523      buffer.append('}');
524    }
525
526    buffer.append(')');
527  }
528}