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;
026import java.util.Collections;
027import java.util.Iterator;
028import java.util.List;
029
030import com.unboundid.asn1.ASN1Element;
031import com.unboundid.asn1.ASN1OctetString;
032import com.unboundid.asn1.ASN1Sequence;
033import com.unboundid.ldap.sdk.Control;
034import com.unboundid.ldap.sdk.ExtendedRequest;
035import com.unboundid.ldap.sdk.ExtendedResult;
036import com.unboundid.ldap.sdk.LDAPConnection;
037import com.unboundid.ldap.sdk.LDAPException;
038import com.unboundid.ldap.sdk.ResultCode;
039import com.unboundid.util.Debug;
040import com.unboundid.util.NotMutable;
041import com.unboundid.util.ObjectPair;
042import com.unboundid.util.StaticUtils;
043import com.unboundid.util.ThreadSafety;
044import com.unboundid.util.ThreadSafetyLevel;
045import com.unboundid.util.Validator;
046
047import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
048
049
050
051/**
052 * This class provides an implementation of an extended request that can be used
053 * to trigger the delivery of a temporary one-time password reset token to a
054 * specified user.  This token can be provided to the password modify extended
055 * request in lieu of the current password for the purpose of performing a self
056 * change and setting a new password.  This token cannot be used to authenticate
057 * to the server in any other way, and it can only be used once.  The token will
058 * expire after a short period of time, and any attempt to use it after its
059 * expiration will fail.  In addition, because this token is only intended for
060 * use in the event that the current password cannot be used (e.g., because it
061 * has been forgotten or the account is locked), a successful bind with the
062 * current password will cause the server to invalidate any password reset token
063 * for that user.
064 * <BR>
065 * <BLOCKQUOTE>
066 *   <B>NOTE:</B>  This class, and other classes within the
067 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
068 *   supported for use against Ping Identity, UnboundID, and
069 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
070 *   for proprietary functionality or for external specifications that are not
071 *   considered stable or mature enough to be guaranteed to work in an
072 *   interoperable way with other types of LDAP servers.
073 * </BLOCKQUOTE>
074 * <BR>
075 * The server will use the same mechanisms for delivering password reset tokens
076 * as it uses for delivering one-time passwords via the
077 * {@link DeliverOneTimePasswordExtendedRequest}.  See the
078 * ds-supported-otp-delivery-mechanism attribute in the root DSE for a list of
079 * the one-time password delivery mechanisms that are configured for use in the
080 * server.
081 * <BR><BR>
082 * This extended request is expected to be used to help applications provide a
083 * secure, automated password reset feature.  In the event that a user has
084 * forgotten his/her password, has allowed the password to expire, or has
085 * allowed the account to become locked, the application can collect a
086 * sufficient set of information to identify the user and request that the
087 * server generate and deliver the password reset token to the end user.
088 * <BR><BR>
089 * The OID for this extended request is 1.3.6.1.4.1.30221.2.6.45.  It must have
090 * a value with the following encoding:
091 * <PRE>
092 *   DeliverPasswordResetTokenRequestValue ::= SEQUENCE {
093 *        userDN                         LDAPDN,
094 *        messageSubject                 [0] OCTET STRING OPTIONAL,
095 *        fullTextBeforeToken            [1] OCTET STRING OPTIONAL,
096 *        fullTextAfterToken             [2] OCTET STRING OPTIONAL,
097 *        compactTextBeforeToken         [3] OCTET STRING OPTIONAL,
098 *        compactTextAfterToken          [4] OCTET STRING OPTIONAL,
099 *        preferredDeliveryMechanism     [5] SEQUENCE OF SEQUENCE {
100 *             mechanismName     OCTET STRING,
101 *             recipientID       OCTET STRING OPTIONAL },
102 *        ... }
103 * </PRE>
104 *
105 * @see  DeliverPasswordResetTokenExtendedResult
106 */
107@NotMutable()
108@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
109public final class DeliverPasswordResetTokenExtendedRequest
110       extends ExtendedRequest
111{
112  /**
113   * The OID (1.3.6.1.4.1.30221.2.6.45) for the deliver password reset token
114   * extended request.
115   */
116  public static final String DELIVER_PW_RESET_TOKEN_REQUEST_OID =
117       "1.3.6.1.4.1.30221.2.6.45";
118
119
120
121  /**
122   * The BER type for the "message subject" element of the value sequence.
123   */
124  private static final byte MESSAGE_SUBJECT_BER_TYPE = (byte) 0x80;
125
126
127
128  /**
129   * The BER type for the "full text before token" element of the value
130   * sequence.
131   */
132  private static final byte FULL_TEXT_BEFORE_TOKEN_BER_TYPE = (byte) 0x81;
133
134
135
136  /**
137   * The BER type for the "full text after token" element of the value
138   * sequence.
139   */
140  private static final byte FULL_TEXT_AFTER_TOKEN_BER_TYPE = (byte) 0x82;
141
142
143
144  /**
145   * The BER type for the "compact text before token" element of the value
146   * sequence.
147   */
148  private static final byte COMPACT_TEXT_BEFORE_TOKEN_BER_TYPE = (byte) 0x83;
149
150
151
152  /**
153   * The BER type for the "compact text after token" element of the value
154   * sequence.
155   */
156  private static final byte COMPACT_TEXT_AFTER_TOKEN_BER_TYPE = (byte) 0x84;
157
158
159
160  /**
161   * The BER type for the "preferred delivery mechanism" element of the value
162   * sequence.
163   */
164  private static final byte PREFERRED_DELIVERY_MECHANISM_BER_TYPE = (byte) 0xA5;
165
166
167
168  /**
169   * The serial version UID for this serializable class.
170   */
171  private static final long serialVersionUID = 7608072810737347230L;
172
173
174
175  // An ordered list of the preferred delivery mechanisms for the token,
176  // paired with an optional recipient ID for each mechanism.
177  private final List<ObjectPair<String, String>> preferredDeliveryMechanisms;
178
179  // The text to include after the token in a compact message.
180  private final String compactTextAfterToken;
181
182  // The text to include before the token in a compact message.
183  private final String compactTextBeforeToken;
184
185  // The text to include after the token in a message without size constraints.
186  private final String fullTextAfterToken;
187
188  // The text to include before the token in a message without size constraints.
189  private final String fullTextBeforeToken;
190
191  // The text to use as the message subject.
192  private final String messageSubject;
193
194  // The DN of the user to whom the password reset token should be delivered.
195  private final String userDN;
196
197
198
199  /**
200   * Creates a new deliver password reset token extended request with the
201   * provided information.
202   *
203   * @param  userDN                       The DN of the user to whom the
204   *                                      password reset token should be
205   *                                      generated.
206   * @param  preferredDeliveryMechanisms  An optional ordered list of preferred
207   *                                      delivery mechanisms that should be
208   *                                      used to deliver the token to the user.
209   *                                      It may be {@code null} or empty to
210   *                                      allow the server to select an
211   *                                      appropriate delivery mechanism.  If it
212   *                                      is non-{@code null} and non-empty,
213   *                                      then only the listed mechanisms will
214   *                                      be considered for use, even if the
215   *                                      server supports alternate mechanisms
216   *                                      not included in this list.
217   */
218  public DeliverPasswordResetTokenExtendedRequest(final String userDN,
219              final String... preferredDeliveryMechanisms)
220  {
221    this(userDN, preferredMechanismsToList(preferredDeliveryMechanisms));
222  }
223
224
225
226  /**
227   * Creates a new deliver password reset token extended request with the
228   * provided information.
229   *
230   * @param  userDN                       The DN of the user to whom the
231   *                                      password reset token should be
232   *                                      generated.
233   * @param  preferredDeliveryMechanisms  An optional ordered list of preferred
234   *                                      delivery mechanisms that should be
235   *                                      used to deliver the token to the user.
236   *                                      It may be {@code null} or empty to
237   *                                      allow the server to select an
238   *                                      appropriate delivery mechanism.  If it
239   *                                      is non-{@code null} and non-empty,
240   *                                      then only the listed mechanisms will
241   *                                      be considered for use, even if the
242   *                                      server supports alternate mechanisms
243   *                                      not included in this list.  Each
244   *                                      {@code ObjectPair} item must have
245   *                                      a non-{@code null} value for the first
246   *                                      element, which is the name of the
247   *                                      target delivery mechanism.  It may
248   *                                      optionally have a non-{@code null}
249   *                                      value for the second element, which is
250   *                                      a recipient ID to use for that
251   *                                      mechanism (e.g., the target  mobile
252   *                                      phone number for SMS delivery, an
253   *                                      email address for email delivery,
254   *                                      etc.).  If no recipient ID is provided
255   *                                      for a mechanism, then the server will
256   *                                      attempt to select a value for the
257   *                                      user.
258   * @param  controls                     An optional set of controls to include
259   *                                      in the request.  It may be
260   *                                      {@code null} or empty if no controls
261   *                                      should be included in the request.
262   */
263  public DeliverPasswordResetTokenExtendedRequest(final String userDN,
264              final List<ObjectPair<String,String>> preferredDeliveryMechanisms,
265              final Control... controls)
266  {
267    this(userDN, null, null, null, null, null, preferredDeliveryMechanisms,
268         controls);
269  }
270
271
272
273  /**
274   * Creates a new deliver password reset token extended request with the
275   * provided information.
276   *
277   * @param  userDN                       The DN of the user to whom the
278   *                                      password reset token should be
279   *                                      generated.
280   * @param  messageSubject               The text (if any) that should be used
281   *                                      as the message subject if the delivery
282   *                                      mechanism accepts a subject.  This may
283   *                                      be {@code null} if no subject is
284   *                                      required or a subject should be
285   *                                      automatically generated.
286   * @param  fullTextBeforeToken          The text (if any) that should appear
287   *                                      before the generated password reset
288   *                                      token in the message delivered to the
289   *                                      user via a delivery mechanism that
290   *                                      does not impose significant
291   *                                      constraints on message size.  This may
292   *                                      be {@code null} if no text is required
293   *                                      before the token.
294   * @param  fullTextAfterToken           The text (if any) that should appear
295   *                                      after the generated password reset
296   *                                      token in the message delivered to the
297   *                                      user via a delivery mechanism that
298   *                                      does not impose significant
299   *                                      constraints on message size.  This may
300   *                                      be {@code null} if no text is required
301   *                                      after the token.
302   * @param  compactTextBeforeToken       The text (if any) that should appear
303   *                                      before the generated password reset
304   *                                      token in the message delivered to the
305   *                                      user via a delivery mechanism that
306   *                                      imposes significant constraints on
307   *                                      message size.  This may be
308   *                                      {@code null} if no text is required
309   *                                      before the token.
310   * @param  compactTextAfterToken        The text (if any) that should appear
311   *                                      after the generated password reset
312   *                                      token in the message delivered to the
313   *                                      user via a delivery mechanism that
314   *                                      imposes significant constraints on
315   *                                      message size.  This may be
316   *                                      {@code null} if no text is required
317   *                                      after the token.
318   * @param  preferredDeliveryMechanisms  An optional ordered list of preferred
319   *                                      delivery mechanisms that should be
320   *                                      used to deliver the token to the user.
321   *                                      It may be {@code null} or empty to
322   *                                      allow the server to select an
323   *                                      appropriate delivery mechanism.  If it
324   *                                      is non-{@code null} and non-empty,
325   *                                      then only the listed mechanisms will
326   *                                      be considered for use, even if the
327   *                                      server supports alternate mechanisms
328   *                                      not included in this list.  Each
329   *                                      {@code ObjectPair} item must have
330   *                                      a non-{@code null} value for the first
331   *                                      element, which is the name of the
332   *                                      target delivery mechanism.  It may
333   *                                      optionally have a non-{@code null}
334   *                                      value for the second element, which is
335   *                                      a recipient ID to use for that
336   *                                      mechanism (e.g., the target  mobile
337   *                                      phone number for SMS delivery, an
338   *                                      email address for email delivery,
339   *                                      etc.).  If no recipient ID is provided
340   *                                      for a mechanism, then the server will
341   *                                      attempt to select a value for the
342   *                                      user.
343   * @param  controls                     An optional set of controls to include
344   *                                      in the request.  It may be
345   *                                      {@code null} or empty if no controls
346   *                                      should be included in the request.
347   */
348  public DeliverPasswordResetTokenExtendedRequest(final String userDN,
349              final String messageSubject, final String fullTextBeforeToken,
350              final String fullTextAfterToken,
351              final String compactTextBeforeToken,
352              final String compactTextAfterToken,
353              final List<ObjectPair<String,String>> preferredDeliveryMechanisms,
354              final Control... controls)
355  {
356    super(DELIVER_PW_RESET_TOKEN_REQUEST_OID,
357         encodeValue(userDN, messageSubject, fullTextBeforeToken,
358              fullTextAfterToken, compactTextBeforeToken, compactTextAfterToken,
359              preferredDeliveryMechanisms), controls);
360
361    this.userDN                 = userDN;
362    this.messageSubject         = messageSubject;
363    this.fullTextBeforeToken    = fullTextBeforeToken;
364    this.fullTextAfterToken     = fullTextAfterToken;
365    this.compactTextBeforeToken = compactTextBeforeToken;
366    this.compactTextAfterToken  = compactTextAfterToken;
367
368    if (preferredDeliveryMechanisms == null)
369    {
370      this.preferredDeliveryMechanisms = Collections.emptyList();
371    }
372    else
373    {
374      this.preferredDeliveryMechanisms = Collections.unmodifiableList(
375           new ArrayList<>(preferredDeliveryMechanisms));
376    }
377  }
378
379
380
381  /**
382   * Creates a new deliver password reset token extended request that is decoded
383   * from the provided extended request.
384   *
385   * @param  request  The generic extended request to decode as a deliver
386   *                  password reset token request.  It must not be
387   *                  {@code null}.
388   *
389   * @throws  LDAPException  If an unexpected problem occurs.
390   */
391  public DeliverPasswordResetTokenExtendedRequest(final ExtendedRequest request)
392         throws LDAPException
393  {
394    super(request);
395
396    final ASN1OctetString value = request.getValue();
397    if (value == null)
398    {
399      throw new LDAPException(ResultCode.DECODING_ERROR,
400           ERR_DELIVER_PW_RESET_TOKEN_REQUEST_NO_VALUE.get());
401    }
402
403    try
404    {
405      final ASN1Element[] elements =
406           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
407      userDN = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
408
409      String subject = null;
410      String fullBefore = null;
411      String fullAfter = null;
412      String compactBefore = null;
413      String compactAfter = null;
414      final ArrayList<ObjectPair<String,String>> pdmList = new ArrayList<>(10);
415      for (int i=1; i < elements.length; i++)
416      {
417        switch (elements[i].getType())
418        {
419          case MESSAGE_SUBJECT_BER_TYPE:
420            subject =
421                 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
422            break;
423
424          case FULL_TEXT_BEFORE_TOKEN_BER_TYPE:
425            fullBefore =
426                 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
427            break;
428
429          case FULL_TEXT_AFTER_TOKEN_BER_TYPE:
430            fullAfter =
431                 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
432            break;
433
434          case COMPACT_TEXT_BEFORE_TOKEN_BER_TYPE:
435            compactBefore =
436                 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
437            break;
438
439          case COMPACT_TEXT_AFTER_TOKEN_BER_TYPE:
440            compactAfter =
441                 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
442            break;
443
444          case PREFERRED_DELIVERY_MECHANISM_BER_TYPE:
445            final ASN1Element[] pdmElements =
446                 ASN1Sequence.decodeAsSequence(elements[i]).elements();
447            for (final ASN1Element e : pdmElements)
448            {
449              final ASN1Element[] mechElements =
450                   ASN1Sequence.decodeAsSequence(e).elements();
451              final String mech = ASN1OctetString.decodeAsOctetString(
452                   mechElements[0]).stringValue();
453
454              final String recipientID;
455              if (mechElements.length > 1)
456              {
457                recipientID = ASN1OctetString.decodeAsOctetString(
458                     mechElements[1]).stringValue();
459              }
460              else
461              {
462                recipientID = null;
463              }
464
465              pdmList.add(new ObjectPair<>(mech, recipientID));
466            }
467            break;
468
469          default:
470            throw new LDAPException(ResultCode.DECODING_ERROR,
471                 ERR_DELIVER_PW_RESET_TOKEN_REQUEST_UNEXPECTED_TYPE.get(
472                      StaticUtils.toHex(elements[i].getType())));
473        }
474      }
475
476      preferredDeliveryMechanisms = Collections.unmodifiableList(pdmList);
477      messageSubject              = subject;
478      fullTextBeforeToken         = fullBefore;
479      fullTextAfterToken          = fullAfter;
480      compactTextBeforeToken      = compactBefore;
481      compactTextAfterToken       = compactAfter;
482    }
483    catch (final LDAPException le)
484    {
485      Debug.debugException(le);
486      throw le;
487    }
488    catch (final Exception e)
489    {
490      Debug.debugException(e);
491      throw new LDAPException(ResultCode.DECODING_ERROR,
492           ERR_DELIVER_PW_RESET_TOKEN_REQUEST_ERROR_DECODING_VALUE.get(
493                StaticUtils.getExceptionMessage(e)),
494           e);
495    }
496  }
497
498
499
500  /**
501   * Encodes the provided set of preferred delivery mechanisms into a form
502   * acceptable to the constructor that expects an object pair.  All of the
503   * recipient IDs will be {@code null}.
504   *
505   * @param  preferredDeliveryMechanisms  An optional ordered list of preferred
506   *                                      delivery mechanisms that should be
507   *                                      used to deliver the token to the user.
508   *                                      It may be {@code null} or empty to
509   *                                      allow the server to select an
510   *                                      appropriate delivery mechanism.  If it
511   *                                      is non-{@code null} and non-empty,
512   *                                      then only the listed mechanisms will
513   *                                      be considered for use, even if the
514   *                                      server supports alternate mechanisms
515   *                                      not included in this list.
516   *
517   * @return  The resulting list of preferred delivery mechanisms with
518   *          {@code null} recipient IDs.
519   */
520  private static List<ObjectPair<String,String>> preferredMechanismsToList(
521                      final String... preferredDeliveryMechanisms)
522  {
523    if (preferredDeliveryMechanisms == null)
524    {
525      return null;
526    }
527
528    final ArrayList<ObjectPair<String,String>> l =
529         new ArrayList<>(preferredDeliveryMechanisms.length);
530    for (final String s : preferredDeliveryMechanisms)
531    {
532      l.add(new ObjectPair<String,String>(s, null));
533    }
534    return l;
535  }
536
537
538
539  /**
540   * Creates an ASN.1 octet string suitable for use as the value of this
541   * extended request.
542   *
543   * @param  userDN                       The DN of the user to whom the
544   *                                      password reset token should be
545   *                                      generated.
546   * @param  messageSubject               The text (if any) that should be used
547   *                                      as the message subject if the delivery
548   *                                      mechanism accepts a subject.  This may
549   *                                      be {@code null} if no subject is
550   *                                      required or a subject should be
551   *                                      automatically generated.
552   * @param  fullTextBeforeToken          The text (if any) that should appear
553   *                                      before the generated password reset
554   *                                      token in the message delivered to the
555   *                                      user via a delivery mechanism that
556   *                                      does not impose significant
557   *                                      constraints on message size.  This may
558   *                                      be {@code null} if no text is required
559   *                                      before the token.
560   * @param  fullTextAfterToken           The text (if any) that should appear
561   *                                      after the generated password reset
562   *                                      token in the message delivered to the
563   *                                      user via a delivery mechanism that
564   *                                      does not impose significant
565   *                                      constraints on message size.  This may
566   *                                      be {@code null} if no text is required
567   *                                      after the token.
568   * @param  compactTextBeforeToken       The text (if any) that should appear
569   *                                      before the generated password reset
570   *                                      token in the message delivered to the
571   *                                      user via a delivery mechanism that
572   *                                      imposes significant constraints on
573   *                                      message size.  This may be
574   *                                      {@code null} if no text is required
575   *                                      before the token.
576   * @param  compactTextAfterToken        The text (if any) that should appear
577   *                                      after the generated password reset
578   *                                      token in the message delivered to the
579   *                                      user via a delivery mechanism that
580   *                                      imposes significant constraints on
581   *                                      message size.  This may be
582   *                                      {@code null} if no text is required
583   *                                      after the token.
584   * @param  preferredDeliveryMechanisms  An optional ordered list of preferred
585   *                                      delivery mechanisms that should be
586   *                                      used to deliver the token to the user.
587   *                                      It may be {@code null} or empty to
588   *                                      allow the server to select an
589   *                                      appropriate delivery mechanism.  If it
590   *                                      is non-{@code null} and non-empty,
591   *                                      then only the listed mechanisms will
592   *                                      be considered for use, even if the
593   *                                      server supports alternate mechanisms
594   *                                      not included in this list.  Each
595   *                                      {@code ObjectPair} item must have
596   *                                      a non-{@code null} value for the first
597   *                                      element, which is the name of the
598   *                                      target delivery mechanism.  It may
599   *                                      optionally have a non-{@code null}
600   *                                      value for the second element, which is
601   *                                      a recipient ID to use for that
602   *                                      mechanism (e.g., the target  mobile
603   *                                      phone number for SMS delivery, an
604   *                                      email address for email delivery,
605   *                                      etc.).  If no recipient ID is provided
606   *                                      for a mechanism, then the server will
607   *                                      attempt to select a value for the
608   *                                      user.
609   *
610   * @return  The ASN.1 octet string containing the encoded request value.
611   */
612  private static ASN1OctetString encodeValue(final String userDN,
613       final String messageSubject, final String fullTextBeforeToken,
614       final String fullTextAfterToken, final String compactTextBeforeToken,
615       final String compactTextAfterToken,
616       final List<ObjectPair<String,String>> preferredDeliveryMechanisms)
617  {
618    Validator.ensureNotNull(userDN);
619
620    final ArrayList<ASN1Element> elements = new ArrayList<>(7);
621    elements.add(new ASN1OctetString(userDN));
622
623    if (messageSubject != null)
624    {
625      elements.add(new ASN1OctetString(MESSAGE_SUBJECT_BER_TYPE,
626           messageSubject));
627    }
628
629    if (fullTextBeforeToken != null)
630    {
631      elements.add(new ASN1OctetString(FULL_TEXT_BEFORE_TOKEN_BER_TYPE,
632           fullTextBeforeToken));
633    }
634
635    if (fullTextAfterToken != null)
636    {
637      elements.add(new ASN1OctetString(FULL_TEXT_AFTER_TOKEN_BER_TYPE,
638           fullTextAfterToken));
639    }
640
641    if (compactTextBeforeToken != null)
642    {
643      elements.add(new ASN1OctetString(COMPACT_TEXT_BEFORE_TOKEN_BER_TYPE,
644           compactTextBeforeToken));
645    }
646
647    if (compactTextAfterToken != null)
648    {
649      elements.add(new ASN1OctetString(COMPACT_TEXT_AFTER_TOKEN_BER_TYPE,
650           compactTextAfterToken));
651    }
652
653    if ((preferredDeliveryMechanisms != null) &&
654        (! preferredDeliveryMechanisms.isEmpty()))
655    {
656      final ArrayList<ASN1Element> pdmElements =
657           new ArrayList<>(preferredDeliveryMechanisms.size());
658      for (final ObjectPair<String,String> p : preferredDeliveryMechanisms)
659      {
660        if (p.getSecond() == null)
661        {
662          pdmElements.add(new ASN1Sequence(
663               new ASN1OctetString(p.getFirst())));
664        }
665        else
666        {
667          pdmElements.add(new ASN1Sequence(
668               new ASN1OctetString(p.getFirst()),
669               new ASN1OctetString(p.getSecond())));
670        }
671      }
672
673      elements.add(new ASN1Sequence(PREFERRED_DELIVERY_MECHANISM_BER_TYPE,
674           pdmElements));
675    }
676
677    return new ASN1OctetString(new ASN1Sequence(elements).encode());
678  }
679
680
681
682  /**
683   * Retrieves the DN of the user to whom the password reset token should be
684   * delivered.
685   *
686   * @return  The DN of the user to whom the password reset token should be
687   *          delivered.
688   */
689  public String getUserDN()
690  {
691    return userDN;
692  }
693
694
695
696  /**
697   * Retrieves the text (if any) that should be used as the message subject for
698   * delivery mechanisms that can make use of a subject.
699   *
700   * @return  The text that should be used as the message subject for delivery
701   *          mechanisms that can make use of a subject, or {@code null} if no
702   *          subject should be used, or if the delivery mechanism should
703   *          attempt to automatically determine a subject.
704   */
705  public String getMessageSubject()
706  {
707    return messageSubject;
708  }
709
710
711
712  /**
713   * Retrieves the text (if any) that should appear before the single-use token
714   * in the message delivered to the user via a mechanism that does not impose
715   * significant constraints on message size.
716   *
717   * @return  The text that should appear before the single-use token in the
718   *          message delivered to the user via a mechanism that does not impose
719   *          significant constraints on message size, or {@code null} if there
720   *          should not be any text before the token.
721   */
722  public String getFullTextBeforeToken()
723  {
724    return fullTextBeforeToken;
725  }
726
727
728
729  /**
730   * Retrieves the text (if any) that should appear after the single-use token
731   * in the message delivered to the user via a mechanism that does not impose
732   * significant constraints on message size.
733   *
734   * @return  The text that should appear after the single-use token in the
735   *          message delivered to the user via a mechanism that does not impose
736   *          significant constraints on message size, or {@code null} if there
737   *          should not be any text after the token.
738   */
739  public String getFullTextAfterToken()
740  {
741    return fullTextAfterToken;
742  }
743
744
745
746  /**
747   * Retrieves the text (if any) that should appear before the single-use token
748   * in the message delivered to the user via a mechanism that imposes
749   * significant constraints on message size.
750   *
751   * @return  The text that should appear before the single-use token in the
752   *          message delivered to the user via a mechanism that imposes
753   *          significant constraints on message size, or {@code null} if there
754   *          should not be any text before the token.
755   */
756  public String getCompactTextBeforeToken()
757  {
758    return compactTextBeforeToken;
759  }
760
761
762
763  /**
764   * Retrieves the text (if any) that should appear after the single-use token
765   * in the message delivered to the user via a mechanism that imposes
766   * significant constraints on message size.
767   *
768   * @return  The text that should appear after the single-use token in the
769   *          message delivered to the user via a mechanism that imposes
770   *          significant constraints on message size, or {@code null} if there
771   *          should not be any text after the token.
772   */
773  public String getCompactTextAfterToken()
774  {
775    return compactTextAfterToken;
776  }
777
778
779
780  /**
781   * Retrieves an ordered list of the preferred delivery mechanisms that should
782   * be used to provide the password reset token to the user, optionally paired
783   * with a mechanism-specific recipient ID (e.g., a mobile phone number for SMS
784   * delivery, or an email address for email delivery) that can be used in the
785   * delivery.  If this list is non-empty, then the server will use the first
786   * mechanism in the list that the server supports and is available for the
787   * target user, and the server will only consider mechanisms in the provided
788   * list even if the server supports alternate mechanisms that are not
789   * included.  If this list is empty, then the server will attempt to select an
790   * appropriate delivery mechanism for the user.
791   *
792   * @return  An ordered list of the preferred delivery mechanisms for the
793   *          password reset token, or an empty list if none were provided.
794   */
795  public List<ObjectPair<String,String>> getPreferredDeliveryMechanisms()
796  {
797    return preferredDeliveryMechanisms;
798  }
799
800
801
802  /**
803   * {@inheritDoc}
804   */
805  @Override()
806  public DeliverPasswordResetTokenExtendedResult process(
807              final LDAPConnection connection, final int depth)
808         throws LDAPException
809  {
810    final ExtendedResult extendedResponse = super.process(connection, depth);
811    return new DeliverPasswordResetTokenExtendedResult(extendedResponse);
812  }
813
814
815
816  /**
817   * {@inheritDoc}.
818   */
819  @Override()
820  public DeliverPasswordResetTokenExtendedRequest duplicate()
821  {
822    return duplicate(getControls());
823  }
824
825
826
827  /**
828   * {@inheritDoc}.
829   */
830  @Override()
831  public DeliverPasswordResetTokenExtendedRequest duplicate(
832                                                       final Control[] controls)
833  {
834    final DeliverPasswordResetTokenExtendedRequest r =
835         new DeliverPasswordResetTokenExtendedRequest(userDN,
836              messageSubject, fullTextBeforeToken, fullTextAfterToken,
837              compactTextBeforeToken, compactTextAfterToken,
838              preferredDeliveryMechanisms, controls);
839    r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
840    return r;
841  }
842
843
844
845  /**
846   * {@inheritDoc}
847   */
848  @Override()
849  public String getExtendedRequestName()
850  {
851    return INFO_EXTENDED_REQUEST_NAME_DELIVER_PW_RESET_TOKEN.get();
852  }
853
854
855
856  /**
857   * {@inheritDoc}
858   */
859  @Override()
860  public void toString(final StringBuilder buffer)
861  {
862    buffer.append("DeliverPasswordResetTokenExtendedRequest(userDN='");
863    buffer.append(userDN);
864    buffer.append('\'');
865
866    if (messageSubject != null)
867    {
868      buffer.append(", messageSubject='");
869      buffer.append(messageSubject);
870      buffer.append('\'');
871    }
872
873    if (fullTextBeforeToken != null)
874    {
875      buffer.append(", fullTextBeforeToken='");
876      buffer.append(fullTextBeforeToken);
877      buffer.append('\'');
878    }
879
880    if (fullTextAfterToken != null)
881    {
882      buffer.append(", fullTextAfterToken='");
883      buffer.append(fullTextAfterToken);
884      buffer.append('\'');
885    }
886
887    if (compactTextBeforeToken != null)
888    {
889      buffer.append(", compactTextBeforeToken='");
890      buffer.append(compactTextBeforeToken);
891      buffer.append('\'');
892    }
893
894    if (compactTextAfterToken != null)
895    {
896      buffer.append(", compactTextAfterToken='");
897      buffer.append(compactTextAfterToken);
898      buffer.append('\'');
899    }
900
901    if (preferredDeliveryMechanisms != null)
902    {
903      buffer.append(", preferredDeliveryMechanisms={");
904
905      final Iterator<ObjectPair<String,String>> iterator =
906           preferredDeliveryMechanisms.iterator();
907      while (iterator.hasNext())
908      {
909        final ObjectPair<String,String> p = iterator.next();
910        buffer.append('\'');
911        buffer.append(p.getFirst());
912        if (p.getSecond() != null)
913        {
914          buffer.append('(');
915          buffer.append(p.getSecond());
916          buffer.append(')');
917        }
918        buffer.append('\'');
919        if (iterator.hasNext())
920        {
921          buffer.append(',');
922        }
923      }
924    }
925
926    final Control[] controls = getControls();
927    if (controls.length > 0)
928    {
929      buffer.append(", controls={");
930      for (int i=0; i < controls.length; i++)
931      {
932        if (i > 0)
933        {
934          buffer.append(", ");
935        }
936
937        buffer.append(controls[i]);
938      }
939      buffer.append('}');
940    }
941
942    buffer.append(')');
943  }
944}