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