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