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