001/* 002 * Copyright 2013-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2013-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.LinkedHashSet; 044import java.util.List; 045 046import com.unboundid.asn1.ASN1Element; 047import com.unboundid.asn1.ASN1OctetString; 048import com.unboundid.asn1.ASN1Sequence; 049import com.unboundid.ldap.sdk.Control; 050import com.unboundid.ldap.sdk.ExtendedRequest; 051import com.unboundid.ldap.sdk.ExtendedResult; 052import com.unboundid.ldap.sdk.LDAPConnection; 053import com.unboundid.ldap.sdk.LDAPException; 054import com.unboundid.ldap.sdk.ResultCode; 055import com.unboundid.util.Debug; 056import com.unboundid.util.NotMutable; 057import com.unboundid.util.ObjectPair; 058import com.unboundid.util.StaticUtils; 059import com.unboundid.util.ThreadSafety; 060import com.unboundid.util.ThreadSafetyLevel; 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 may be used 068 * to request that the Directory Server deliver a one-time password to an end 069 * user that they may use to authenticate via an 070 * {@link com.unboundid.ldap.sdk.unboundidds.UnboundIDDeliveredOTPBindRequest}. 071 * <BR> 072 * <BLOCKQUOTE> 073 * <B>NOTE:</B> This class, and other classes within the 074 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 075 * supported for use against Ping Identity, UnboundID, and 076 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 077 * for proprietary functionality or for external specifications that are not 078 * considered stable or mature enough to be guaranteed to work in an 079 * interoperable way with other types of LDAP servers. 080 * </BLOCKQUOTE> 081 * <BR> 082 * Notes on the recommended use of this extended request: 083 * <UL> 084 * <LI>Whenever possible, the user's static password should be provided. 085 * However, the server will allow the static password to be omitted if the 086 * authentication ID included in the request matches the authorization 087 * identity of the extended operation (either because that user is already 088 * authenticated on the connection, or because the request includes a 089 * proxied authorization or intermediate client control specifying that 090 * identity). In that case, the operation will be able to act as a 091 * "step-up" mechanism, providing further proof of the identity of an 092 * already-authenticated client rather than performing the complete 093 * authentication process.</LI> 094 * <LI>The request offers two mechanisms for indicating which delivery 095 * mechanism(s) should be considered: an option to specify just the 096 * delivery mechanism names, and an option to specify the names along with 097 * recipient IDs. At most one of these elements must be present in the 098 * request. If neither is present, the server will attempt to determine 099 * which delivery mechanisms and recipient IDs should be used. If the 100 * set of preferred delivery mechanisms includes multiple items, the 101 * server will attempt them in the order provided until it is able to 102 * successfully deliver the message. The server will not attempt to 103 * use any other delivery mechanisms that may be configured if the request 104 * includes a list of preferred delivery mechanisms.</LI> 105 * <LI>Although the message elements (message subject, and full and compact 106 * text before and after the OTP) are optional, it is recommended that 107 * they be supplied by the client. The server will provide a generic 108 * message if no message elements are included in the request.</LI> 109 * </UL> 110 * <BR><BR> 111 * The OID for this extended request is 1.3.6.1.4.1.30221.2.6.24. It must have 112 * a value, and that value should have the following encoding: 113 * <BR><BR> 114 * <PRE> 115 * DeliverOTPRequest ::= SEQUENCE { 116 * authenticationID [0] OCTET STRING, 117 * staticPassword [1] OCTET STRING OPTIONAL, 118 * preferredMechNames [2] SEQUENCE OF OCTET STRING OPTIONAL, 119 * preferredMechNamesAndIDs [3] SEQUENCE OF SEQUENCE, 120 * mechanismName OCTET STRING, 121 * recipientID OCTET STRING OPTIONAL } OPTIONAL, 122 * messageSubject [4] OCTET STRING OPTIONAL, 123 * fullTextBeforeOTP [5] OCTET STRING OPTIONAL, 124 * fullTextAfterOTP [6] OCTET STRING OPTIONAL, 125 * compactTextBeforeOTP [7] OCTET STRING OPTIONAL, 126 * compactTextAfterOTP [8] OCTET STRING OPTIONAL, 127 * ... } 128 * </PRE> 129 * 130 * @see com.unboundid.ldap.sdk.unboundidds.UnboundIDDeliveredOTPBindRequest 131 * @see DeliverOneTimePasswordExtendedResult 132 */ 133@NotMutable() 134@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 135public final class DeliverOneTimePasswordExtendedRequest 136 extends ExtendedRequest 137{ 138 /** 139 * The OID (1.3.6.1.4.1.30221.2.6.24) for the deliver one-time password 140 * extended request. 141 */ 142 public static final String DELIVER_OTP_REQUEST_OID = 143 "1.3.6.1.4.1.30221.2.6.24"; 144 145 146 147 /** 148 * The BER type for the authentication ID element. 149 */ 150 private static final byte TYPE_AUTHN_ID = (byte) 0x80; 151 152 153 154 /** 155 * The BER type for the static password element. 156 */ 157 private static final byte TYPE_PASSWORD = (byte) 0x81; 158 159 160 161 /** 162 * The BER type for the preferred delivery mechanism names element.. 163 */ 164 private static final byte TYPE_PREFERRED_DELIVERY_MECHANISM_NAMES = 165 (byte) 0xA2; 166 167 168 169 /** 170 * The BER type for the preferred delivery mechanism names and IDs element.. 171 */ 172 private static final byte TYPE_PREFERRED_DELIVERY_MECHANISM_NAMES_AND_IDS = 173 (byte) 0xA3; 174 175 176 177 /** 178 * The BER type for the "message subject" element of the value sequence. 179 */ 180 private static final byte MESSAGE_SUBJECT_BER_TYPE = (byte) 0x84; 181 182 183 184 /** 185 * The BER type for the "full text before OTP" element of the value 186 * sequence. 187 */ 188 private static final byte FULL_TEXT_BEFORE_OTP_BER_TYPE = (byte) 0x85; 189 190 191 192 /** 193 * The BER type for the "full text after OTP" element of the value 194 * sequence. 195 */ 196 private static final byte FULL_TEXT_AFTER_OTP_BER_TYPE = (byte) 0x86; 197 198 199 200 /** 201 * The BER type for the "compact text before OTP" element of the value 202 * sequence. 203 */ 204 private static final byte COMPACT_TEXT_BEFORE_OTP_BER_TYPE = (byte) 0x87; 205 206 207 208 /** 209 * The BER type for the "compact text after OTP" element of the value 210 * sequence. 211 */ 212 private static final byte COMPACT_TEXT_AFTER_OTP_BER_TYPE = (byte) 0x88; 213 214 215 216 /** 217 * The serial version UID for this serializable class. 218 */ 219 private static final long serialVersionUID = 1259250969726758847L; 220 221 222 223 // The static password to include in the request. 224 private final ASN1OctetString staticPassword; 225 226 // The list of preferred delivery mechanisms to include in the request. 227 private final List<ObjectPair<String, String>> preferredDeliveryMechanisms; 228 229 // The authentication ID to include in the request. 230 private final String authenticationID; 231 232 // The text to include after the OTP in a compact message. 233 private final String compactTextAfterOTP; 234 235 // The text to include before the OTP in a compact message. 236 private final String compactTextBeforeOTP; 237 238 // The text to include after the OTP in a message without size constraints. 239 private final String fullTextAfterOTP; 240 241 // The text to include before the OTP in a message without size constraints. 242 private final String fullTextBeforeOTP; 243 244 // The text to use as the message subject. 245 private final String messageSubject; 246 247 248 249 /** 250 * Creates a new deliver one-time password extended request with the provided 251 * information. 252 * 253 * @param authenticationID The authentication ID for the user to 254 * whom the one-time password should be 255 * delivered. It must not be 256 * {@code null}. 257 * @param staticPassword The static password for the user to 258 * whom the one-time password should be 259 * delivered. It may be {@code null} if 260 * this request is intended to be used 261 * to step-up an existing authentication 262 * rather than perform a new 263 * authentication (in which case the 264 * provided authentication ID must match 265 * the operation's authorization ID). 266 * @param preferredDeliveryMechanisms The names of the preferred delivery 267 * mechanisms for the one-time password. 268 * It may be {@code null} or empty if the 269 * server should select an appropriate 270 * delivery mechanism. If it is 271 * non-{@code null} and non-empty, then 272 * only the listed mechanisms will be 273 * considered for use, even if the server 274 * supports alternate mechanisms not 275 * included in this list. 276 */ 277 public DeliverOneTimePasswordExtendedRequest(final String authenticationID, 278 final String staticPassword, 279 final String... preferredDeliveryMechanisms) 280 { 281 this(authenticationID, staticPassword, 282 StaticUtils.toList(preferredDeliveryMechanisms)); 283 } 284 285 286 287 /** 288 * Creates a new deliver one-time password extended request with the provided 289 * information. 290 * 291 * @param authenticationID The authentication ID for the user to 292 * whom the one-time password should be 293 * delivered. It must not be 294 * {@code null}. 295 * @param staticPassword The static password for the user to 296 * whom the one-time password should be 297 * delivered. It may be {@code null} if 298 * this request is intended to be used 299 * to step-up an existing authentication 300 * rather than perform a new 301 * authentication (in which case the 302 * provided authentication ID must match 303 * the operation's authorization ID). 304 * @param preferredDeliveryMechanisms The names of the preferred delivery 305 * mechanisms for the one-time password. 306 * It may be {@code null} or empty if the 307 * server should select an appropriate 308 * delivery mechanism. If it is 309 * non-{@code null} and non-empty, then 310 * only the listed mechanisms will be 311 * considered for use, even if the server 312 * supports alternate mechanisms not 313 * included in this list. 314 */ 315 public DeliverOneTimePasswordExtendedRequest(final String authenticationID, 316 final byte[] staticPassword, 317 final String... preferredDeliveryMechanisms) 318 { 319 this(authenticationID, staticPassword, 320 StaticUtils.toList(preferredDeliveryMechanisms)); 321 } 322 323 324 325 /** 326 * Creates a new deliver one-time password extended request with the provided 327 * information. 328 * 329 * @param authenticationID The authentication ID for the user to 330 * whom the one-time password should be 331 * delivered. It must not be 332 * {@code null}. 333 * @param staticPassword The static password for the user to 334 * whom the one-time password should be 335 * delivered. It may be {@code null} if 336 * this request is intended to be used 337 * to step-up an existing authentication 338 * rather than perform a new 339 * authentication (in which case the 340 * provided authentication ID must match 341 * the operation's authorization ID). 342 * @param preferredDeliveryMechanisms The names of the preferred delivery 343 * mechanisms for the one-time password. 344 * It may be {@code null} or empty if the 345 * server should select an appropriate 346 * delivery mechanism. If it is 347 * non-{@code null} and non-empty, then 348 * only the listed mechanisms will be 349 * considered for use, even if the server 350 * supports alternate mechanisms not 351 * included in this list. 352 * @param controls The set of controls to include in the 353 * request. It may be {@code null} or 354 * empty if no controls should be 355 * included. 356 */ 357 public DeliverOneTimePasswordExtendedRequest(final String authenticationID, 358 final String staticPassword, 359 final List<String> preferredDeliveryMechanisms, 360 final Control... controls) 361 { 362 this(authenticationID, 363 (staticPassword == null 364 ? null 365 : new ASN1OctetString(TYPE_PASSWORD, staticPassword)), 366 preferredDeliveryMechanisms, controls); 367 } 368 369 370 371 /** 372 * Creates a new deliver one-time password extended request with the provided 373 * information. 374 * 375 * @param authenticationID The authentication ID for the user to 376 * whom the one-time password should be 377 * delivered. It must not be 378 * {@code null}. 379 * @param staticPassword The static password for the user to 380 * whom the one-time password should be 381 * delivered. It may be {@code null} if 382 * this request is intended to be used 383 * to step-up an existing authentication 384 * rather than perform a new 385 * authentication (in which case the 386 * provided authentication ID must match 387 * the operation's authorization ID). 388 * @param preferredDeliveryMechanisms The names of the preferred delivery 389 * mechanisms for the one-time password. 390 * It may be {@code null} or empty if the 391 * server should select an appropriate 392 * delivery mechanism. If it is 393 * non-{@code null} and non-empty, then 394 * only the listed mechanisms will be 395 * considered for use, even if the server 396 * supports alternate mechanisms not 397 * included in this list. 398 * @param controls The set of controls to include in the 399 * request. It may be {@code null} or 400 * empty if no controls should be 401 * included. 402 */ 403 public DeliverOneTimePasswordExtendedRequest(final String authenticationID, 404 final byte[] staticPassword, 405 final List<String> preferredDeliveryMechanisms, 406 final Control... controls) 407 { 408 this(authenticationID, 409 (staticPassword == null 410 ? null 411 : new ASN1OctetString(TYPE_PASSWORD, staticPassword)), 412 preferredDeliveryMechanisms, controls); 413 } 414 415 416 417 /** 418 * Creates a new deliver one-time password extended request with the provided 419 * information. 420 * 421 * @param authenticationID The authentication ID for the user to 422 * whom the one-time password should be 423 * delivered. It must not be 424 * {@code null}. 425 * @param staticPassword The static password for the user to 426 * whom the one-time password should be 427 * delivered. It may be {@code null} if 428 * this request is intended to be used 429 * to step-up an existing authentication 430 * rather than perform a new 431 * authentication (in which case the 432 * provided authentication ID must match 433 * the operation's authorization ID). 434 * @param preferredDeliveryMechanisms The names of the preferred delivery 435 * mechanisms for the one-time password. 436 * It may be {@code null} or empty if the 437 * server should select an appropriate 438 * delivery mechanism. If it is 439 * non-{@code null} and non-empty, then 440 * only the listed mechanisms will be 441 * considered for use, even if the server 442 * supports alternate mechanisms not 443 * included in this list. 444 * @param controls The set of controls to include in the 445 * request. It may be {@code null} or 446 * empty if no controls should be 447 * included. 448 */ 449 private DeliverOneTimePasswordExtendedRequest(final String authenticationID, 450 final ASN1OctetString staticPassword, 451 final List<String> preferredDeliveryMechanisms, 452 final Control... controls) 453 { 454 super(DELIVER_OTP_REQUEST_OID, 455 encodeValue(authenticationID, staticPassword, 456 preferredDeliveryMechanisms), 457 controls); 458 459 this.authenticationID = authenticationID; 460 this.staticPassword = staticPassword; 461 462 if ((preferredDeliveryMechanisms == null) || 463 preferredDeliveryMechanisms.isEmpty()) 464 { 465 this.preferredDeliveryMechanisms = Collections.emptyList(); 466 } 467 else 468 { 469 final ArrayList<ObjectPair<String,String>> l = 470 new ArrayList<>(preferredDeliveryMechanisms.size()); 471 for (final String s : preferredDeliveryMechanisms) 472 { 473 l.add(new ObjectPair<String,String>(s, null)); 474 } 475 this.preferredDeliveryMechanisms = Collections.unmodifiableList(l); 476 } 477 478 messageSubject = null; 479 fullTextBeforeOTP = null; 480 fullTextAfterOTP = null; 481 compactTextBeforeOTP = null; 482 compactTextAfterOTP = null; 483 } 484 485 486 487 /** 488 * Creates a new deliver one-time password extended request with the provided 489 * information. 490 * 491 * @param authenticationID The authentication ID for the user to 492 * whom the one-time password should be 493 * delivered. It must not be 494 * {@code null}. 495 * @param staticPassword The static password for the user to 496 * whom the one-time password should be 497 * delivered. It may be {@code null} if 498 * this request is intended to be used 499 * to step-up an existing authentication 500 * rather than perform a new 501 * authentication (in which case the 502 * provided authentication ID must match 503 * the operation's authorization ID). 504 * @param messageSubject The text (if any) that should be used 505 * as the message subject if the delivery 506 * mechanism accepts a subject. This may 507 * be {@code null} if no subject is 508 * required or a subject should be 509 * automatically generated. 510 * @param fullTextBeforeOTP The text (if any) that should appear 511 * before the generated one-time password 512 * in the message delivered to the user 513 * via a delivery mechanism that does not 514 * impose significant constraints on 515 * message size. This may be 516 * {@code null} if no text is required 517 * before the one-time password. 518 * @param fullTextAfterOTP The text (if any) that should appear 519 * after the one-time password in the 520 * message delivered to the user via a 521 * delivery mechanism that does not 522 * impose significant constraints on 523 * message size. This may be 524 * {@code null} if no text is required 525 * after the one-time password. 526 * @param compactTextBeforeOTP The text (if any) that should appear 527 * before the generated one-time password 528 * in the message delivered to the user 529 * via a delivery mechanism that imposes 530 * significant constraints on message 531 * size. This may be {@code null} if no 532 * text is required before the one-time 533 * password. 534 * @param compactTextAfterOTP The text (if any) that should appear 535 * after the generated one-time password 536 * in the message delivered to the user 537 * via a delivery mechanism that imposes 538 * significant constraints on message 539 * size. This may be {@code null} if no 540 * text is required after the one-time 541 * password. 542 * @param preferredDeliveryMechanisms An optional ordered list of preferred 543 * delivery mechanisms that should be 544 * used to deliver the one-time password 545 * to the user. It may be {@code null} 546 * or empty to allow the server to select 547 * an appropriate delivery mechanism. If 548 * it is non-{@code null} and non-empty, 549 * then only the listed mechanisms will 550 * be considered for use, even if the 551 * server supports alternate mechanisms 552 * not included in this list. Each 553 * {@code ObjectPair} item must have 554 * a non-{@code null} value for the first 555 * element, which is the name of the 556 * target delivery mechanism. It may 557 * optionally have a non-{@code null} 558 * value for the second element, which is 559 * a recipient ID to use for that 560 * mechanism (e.g., the target mobile 561 * phone number for SMS delivery, an 562 * email address for email delivery, 563 * etc.). If no recipient ID is provided 564 * for a mechanism, then the server will 565 * attempt to select a value for the 566 * user. 567 * @param controls The set of controls to include in the 568 * request. It may be {@code null} or 569 * empty if no controls should be 570 * included. 571 */ 572 public DeliverOneTimePasswordExtendedRequest(final String authenticationID, 573 final String staticPassword, final String messageSubject, 574 final String fullTextBeforeOTP, final String fullTextAfterOTP, 575 final String compactTextBeforeOTP, final String compactTextAfterOTP, 576 final List<ObjectPair<String,String>> preferredDeliveryMechanisms, 577 final Control... controls) 578 { 579 this(authenticationID, 580 (staticPassword == null 581 ? null 582 : new ASN1OctetString(TYPE_PASSWORD, staticPassword)), 583 messageSubject, fullTextBeforeOTP, fullTextAfterOTP, 584 compactTextBeforeOTP, compactTextAfterOTP, preferredDeliveryMechanisms, 585 controls); 586 } 587 588 589 590 /** 591 * Creates a new deliver one-time password extended request with the provided 592 * information. 593 * 594 * @param authenticationID The authentication ID for the user to 595 * whom the one-time password should be 596 * delivered. It must not be 597 * {@code null}. 598 * @param staticPassword The static password for the user to 599 * whom the one-time password should be 600 * delivered. It may be {@code null} if 601 * this request is intended to be used 602 * to step-up an existing authentication 603 * rather than perform a new 604 * authentication (in which case the 605 * provided authentication ID must match 606 * the operation's authorization ID). 607 * @param messageSubject The text (if any) that should be used 608 * as the message subject if the delivery 609 * mechanism accepts a subject. This may 610 * be {@code null} if no subject is 611 * required or a subject should be 612 * automatically generated. 613 * @param fullTextBeforeOTP The text (if any) that should appear 614 * before the generated one-time password 615 * in the message delivered to the user 616 * via a delivery mechanism that does not 617 * impose significant constraints on 618 * message size. This may be 619 * {@code null} if no text is required 620 * before the one-time password. 621 * @param fullTextAfterOTP The text (if any) that should appear 622 * after the one-time password in the 623 * message delivered to the user via a 624 * delivery mechanism that does not 625 * impose significant constraints on 626 * message size. This may be 627 * {@code null} if no text is required 628 * after the one-time password. 629 * @param compactTextBeforeOTP The text (if any) that should appear 630 * before the generated one-time password 631 * in the message delivered to the user 632 * via a delivery mechanism that imposes 633 * significant constraints on message 634 * size. This may be {@code null} if no 635 * text is required before the one-time 636 * password. 637 * @param compactTextAfterOTP The text (if any) that should appear 638 * after the generated one-time password 639 * in the message delivered to the user 640 * via a delivery mechanism that imposes 641 * significant constraints on message 642 * size. This may be {@code null} if no 643 * text is required after the one-time 644 * password. 645 * @param preferredDeliveryMechanisms An optional ordered list of preferred 646 * delivery mechanisms that should be 647 * used to deliver the one-time password 648 * to the user. It may be {@code null} 649 * or empty to allow the server to select 650 * an appropriate delivery mechanism. If 651 * it is non-{@code null} and non-empty, 652 * then only the listed mechanisms will 653 * be considered for use, even if the 654 * server supports alternate mechanisms 655 * not included in this list. Each 656 * {@code ObjectPair} item must have 657 * a non-{@code null} value for the first 658 * element, which is the name of the 659 * target delivery mechanism. It may 660 * optionally have a non-{@code null} 661 * value for the second element, which is 662 * a recipient ID to use for that 663 * mechanism (e.g., the target mobile 664 * phone number for SMS delivery, an 665 * email address for email delivery, 666 * etc.). If no recipient ID is provided 667 * for a mechanism, then the server will 668 * attempt to select a value for the 669 * user. 670 * @param controls The set of controls to include in the 671 * request. It may be {@code null} or 672 * empty if no controls should be 673 * included. 674 */ 675 public DeliverOneTimePasswordExtendedRequest(final String authenticationID, 676 final byte[] staticPassword, final String messageSubject, 677 final String fullTextBeforeOTP, final String fullTextAfterOTP, 678 final String compactTextBeforeOTP, final String compactTextAfterOTP, 679 final List<ObjectPair<String,String>> preferredDeliveryMechanisms, 680 final Control... controls) 681 { 682 this(authenticationID, 683 (staticPassword == null 684 ? null 685 : new ASN1OctetString(TYPE_PASSWORD, staticPassword)), 686 messageSubject, fullTextBeforeOTP, fullTextAfterOTP, 687 compactTextBeforeOTP, compactTextAfterOTP, preferredDeliveryMechanisms, 688 controls); 689 } 690 691 692 693 /** 694 * Creates a new deliver one-time password extended request with the provided 695 * information. 696 * 697 * @param authenticationID The authentication ID for the user to 698 * whom the one-time password should be 699 * delivered. It must not be 700 * {@code null}. 701 * @param staticPassword The static password for the user to 702 * whom the one-time password should be 703 * delivered. It may be {@code null} if 704 * this request is intended to be used 705 * to step-up an existing authentication 706 * rather than perform a new 707 * authentication (in which case the 708 * provided authentication ID must match 709 * the operation's authorization ID). 710 * @param messageSubject The text (if any) that should be used 711 * as the message subject if the delivery 712 * mechanism accepts a subject. This may 713 * be {@code null} if no subject is 714 * required or a subject should be 715 * automatically generated. 716 * @param fullTextBeforeOTP The text (if any) that should appear 717 * before the generated one-time password 718 * in the message delivered to the user 719 * via a delivery mechanism that does not 720 * impose significant constraints on 721 * message size. This may be 722 * {@code null} if no text is required 723 * before the one-time password. 724 * @param fullTextAfterOTP The text (if any) that should appear 725 * after the one-time password in the 726 * message delivered to the user via a 727 * delivery mechanism that does not 728 * impose significant constraints on 729 * message size. This may be 730 * {@code null} if no text is required 731 * after the one-time password. 732 * @param compactTextBeforeOTP The text (if any) that should appear 733 * before the generated one-time password 734 * in the message delivered to the user 735 * via a delivery mechanism that imposes 736 * significant constraints on message 737 * size. This may be {@code null} if no 738 * text is required before the one-time 739 * password. 740 * @param compactTextAfterOTP The text (if any) that should appear 741 * after the generated one-time password 742 * in the message delivered to the user 743 * via a delivery mechanism that imposes 744 * significant constraints on message 745 * size. This may be {@code null} if no 746 * text is required after the one-time 747 * password. 748 * @param preferredDeliveryMechanisms An optional ordered list of preferred 749 * delivery mechanisms that should be 750 * used to deliver the one-time password 751 * to the user. It may be {@code null} 752 * or empty to allow the server to select 753 * an appropriate delivery mechanism. If 754 * it is non-{@code null} and non-empty, 755 * then only the listed mechanisms will 756 * be considered for use, even if the 757 * server supports alternate mechanisms 758 * not included in this list. Each 759 * {@code ObjectPair} item must have 760 * a non-{@code null} value for the first 761 * element, which is the name of the 762 * target delivery mechanism. It may 763 * optionally have a non-{@code null} 764 * value for the second element, which is 765 * a recipient ID to use for that 766 * mechanism (e.g., the target mobile 767 * phone number for SMS delivery, an 768 * email address for email delivery, 769 * etc.). If no recipient ID is provided 770 * for a mechanism, then the server will 771 * attempt to select a value for the 772 * user. 773 * @param controls The set of controls to include in the 774 * request. It may be {@code null} or 775 * empty if no controls should be 776 * included. 777 */ 778 private DeliverOneTimePasswordExtendedRequest(final String authenticationID, 779 final ASN1OctetString staticPassword, final String messageSubject, 780 final String fullTextBeforeOTP, final String fullTextAfterOTP, 781 final String compactTextBeforeOTP, final String compactTextAfterOTP, 782 final List<ObjectPair<String,String>> preferredDeliveryMechanisms, 783 final Control... controls) 784 { 785 super(DELIVER_OTP_REQUEST_OID, 786 encodeValue(authenticationID, staticPassword, messageSubject, 787 fullTextBeforeOTP, fullTextAfterOTP, compactTextBeforeOTP, 788 compactTextAfterOTP, preferredDeliveryMechanisms), 789 controls); 790 791 this.authenticationID = authenticationID; 792 this.staticPassword = staticPassword; 793 this.messageSubject = messageSubject; 794 this.fullTextBeforeOTP = fullTextBeforeOTP; 795 this.fullTextAfterOTP = fullTextAfterOTP; 796 this.compactTextBeforeOTP = compactTextBeforeOTP; 797 this.compactTextAfterOTP = compactTextAfterOTP; 798 799 if ((preferredDeliveryMechanisms == null) || 800 preferredDeliveryMechanisms.isEmpty()) 801 { 802 this.preferredDeliveryMechanisms = Collections.emptyList(); 803 } 804 else 805 { 806 this.preferredDeliveryMechanisms = 807 Collections.unmodifiableList(preferredDeliveryMechanisms); 808 } 809 } 810 811 812 813 /** 814 * Creates a new deliver one-time password extended request from the 815 * information contained in the provided generic extended request. 816 * 817 * @param request The generic extended request to be decoded as a deliver 818 * one-time password extended request. 819 * 820 * @throws LDAPException If a problem is encountered while attempting to 821 * decode the provided generic extended request as a 822 * deliver one-time password extended request. 823 */ 824 public DeliverOneTimePasswordExtendedRequest(final ExtendedRequest request) 825 throws LDAPException 826 { 827 super(request); 828 829 // The request must have a value. 830 final ASN1OctetString value = request.getValue(); 831 if (value == null) 832 { 833 throw new LDAPException(ResultCode.DECODING_ERROR, 834 ERR_DELIVER_OTP_REQ_NO_VALUE.get()); 835 } 836 837 838 // Parse the value. 839 ASN1OctetString password = null; 840 String authnID = null; 841 String subject = null; 842 String fullBefore = null; 843 String fullAfter = null; 844 String compactBefore = null; 845 String compactAfter = null; 846 final ArrayList<ObjectPair<String,String>> pdmList = new ArrayList<>(10); 847 try 848 { 849 for (final ASN1Element e : 850 ASN1Sequence.decodeAsSequence(value.getValue()).elements()) 851 { 852 switch (e.getType()) 853 { 854 case TYPE_AUTHN_ID: 855 authnID = ASN1OctetString.decodeAsOctetString(e).stringValue(); 856 break; 857 858 case TYPE_PASSWORD: 859 password = ASN1OctetString.decodeAsOctetString(e); 860 break; 861 862 case TYPE_PREFERRED_DELIVERY_MECHANISM_NAMES: 863 final ASN1Element[] mechNameElements = 864 ASN1Sequence.decodeAsSequence(e).elements(); 865 for (final ASN1Element mechElement : mechNameElements) 866 { 867 pdmList.add(new ObjectPair<String,String>( 868 ASN1OctetString.decodeAsOctetString(mechElement). 869 stringValue(), 870 null)); 871 } 872 break; 873 874 case TYPE_PREFERRED_DELIVERY_MECHANISM_NAMES_AND_IDS: 875 final ASN1Element[] pdmElements = 876 ASN1Sequence.decodeAsSequence(e).elements(); 877 for (final ASN1Element pdmElement : pdmElements) 878 { 879 final ASN1Element[] mechElements = 880 ASN1Sequence.decodeAsSequence(pdmElement).elements(); 881 final String mech = ASN1OctetString.decodeAsOctetString( 882 mechElements[0]).stringValue(); 883 884 final String recipientID; 885 if (mechElements.length > 1) 886 { 887 recipientID = ASN1OctetString.decodeAsOctetString( 888 mechElements[1]).stringValue(); 889 } 890 else 891 { 892 recipientID = null; 893 } 894 895 pdmList.add(new ObjectPair<>(mech, recipientID)); 896 } 897 break; 898 899 case MESSAGE_SUBJECT_BER_TYPE: 900 subject = 901 ASN1OctetString.decodeAsOctetString(e).stringValue(); 902 break; 903 904 case FULL_TEXT_BEFORE_OTP_BER_TYPE: 905 fullBefore = 906 ASN1OctetString.decodeAsOctetString(e).stringValue(); 907 break; 908 909 case FULL_TEXT_AFTER_OTP_BER_TYPE: 910 fullAfter = 911 ASN1OctetString.decodeAsOctetString(e).stringValue(); 912 break; 913 914 case COMPACT_TEXT_BEFORE_OTP_BER_TYPE: 915 compactBefore = 916 ASN1OctetString.decodeAsOctetString(e).stringValue(); 917 break; 918 919 case COMPACT_TEXT_AFTER_OTP_BER_TYPE: 920 compactAfter = 921 ASN1OctetString.decodeAsOctetString(e).stringValue(); 922 break; 923 924 default: 925 throw new LDAPException(ResultCode.DECODING_ERROR, 926 ERR_DELIVER_OTP_REQ_UNEXPECTED_ELEMENT_TYPE.get( 927 StaticUtils.toHex(e.getType()))); 928 929 } 930 } 931 } 932 catch (final LDAPException le) 933 { 934 Debug.debugException(le); 935 throw le; 936 } 937 catch (final Exception e) 938 { 939 Debug.debugException(e); 940 throw new LDAPException(ResultCode.DECODING_ERROR, 941 ERR_DELIVER_OTP_REQ_ERROR_PARSING_VALUE.get( 942 StaticUtils.getExceptionMessage(e)), 943 e); 944 } 945 946 if (authnID == null) 947 { 948 throw new LDAPException(ResultCode.DECODING_ERROR, 949 ERR_DELIVER_OTP_REQ_NO_AUTHN_ID.get()); 950 } 951 else 952 { 953 authenticationID = authnID; 954 } 955 956 staticPassword = password; 957 messageSubject = subject; 958 fullTextBeforeOTP = fullBefore; 959 fullTextAfterOTP = fullAfter; 960 compactTextBeforeOTP = compactBefore; 961 compactTextAfterOTP = compactAfter; 962 963 if ((pdmList == null) || pdmList.isEmpty()) 964 { 965 preferredDeliveryMechanisms = Collections.emptyList(); 966 } 967 else 968 { 969 preferredDeliveryMechanisms = Collections.unmodifiableList(pdmList); 970 } 971 } 972 973 974 975 /** 976 * Encodes the provided information into an ASN.1 octet string suitable for 977 * use as the value of this extended request. 978 * 979 * @param authenticationID The authentication ID for the user to 980 * whom the one-time password should be 981 * delivered. It must not be 982 * {@code null}. 983 * @param staticPassword The static password for the user to 984 * whom the one-time password should be 985 * delivered. 986 * @param preferredDeliveryMechanisms The names of the preferred delivery 987 * mechanisms for the one-time password. 988 * It may be {@code null} or empty if the 989 * server should select an appropriate 990 * delivery mechanism. If it is 991 * non-{@code null} and non-empty, then 992 * only the listed mechanisms will be 993 * considered for use, even if the server 994 * supports alternate mechanisms not 995 * included in this list. 996 * 997 * @return An ASN.1 octet string suitable for use as the value of this 998 * extended request. 999 */ 1000 private static ASN1OctetString encodeValue(final String authenticationID, 1001 final ASN1OctetString staticPassword, 1002 final List<String> preferredDeliveryMechanisms) 1003 { 1004 final ArrayList<ASN1Element> elements = new ArrayList<>(3); 1005 1006 elements.add(new ASN1OctetString(TYPE_AUTHN_ID, authenticationID)); 1007 1008 if (staticPassword != null) 1009 { 1010 elements.add(staticPassword); 1011 } 1012 1013 if ((preferredDeliveryMechanisms != null) && 1014 (! preferredDeliveryMechanisms.isEmpty())) 1015 { 1016 final ArrayList<ASN1Element> dmElements = 1017 new ArrayList<>(preferredDeliveryMechanisms.size()); 1018 for (final String s : preferredDeliveryMechanisms) 1019 { 1020 dmElements.add(new ASN1OctetString(s)); 1021 } 1022 elements.add(new ASN1Sequence(TYPE_PREFERRED_DELIVERY_MECHANISM_NAMES, 1023 dmElements)); 1024 } 1025 1026 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 1027 } 1028 1029 1030 1031 /** 1032 * Encodes the provided information into an ASN.1 octet string suitable for 1033 * use as the value of this extended request. 1034 * 1035 * @param authenticationID The authentication ID for the user to 1036 * whom the one-time password should be 1037 * delivered. It must not be 1038 * {@code null}. 1039 * @param staticPassword The static password for the user to 1040 * whom the one-time password should be 1041 * delivered. It may be {@code null} if 1042 * this request is intended to be used 1043 * to step-up an existing authentication 1044 * rather than perform a new 1045 * authentication (in which case the 1046 * provided authentication ID must match 1047 * the operation's authorization ID). 1048 * @param messageSubject The text (if any) that should be used 1049 * as the message subject if the delivery 1050 * mechanism accepts a subject. This may 1051 * be {@code null} if no subject is 1052 * required or a subject should be 1053 * automatically generated. 1054 * @param fullTextBeforeOTP The text (if any) that should appear 1055 * before the generated one-time password 1056 * in the message delivered to the user 1057 * via a delivery mechanism that does not 1058 * impose significant constraints on 1059 * message size. This may be 1060 * {@code null} if no text is required 1061 * before the one-time password. 1062 * @param fullTextAfterOTP The text (if any) that should appear 1063 * after the one-time password in the 1064 * message delivered to the user via a 1065 * delivery mechanism that does not 1066 * impose significant constraints on 1067 * message size. This may be 1068 * {@code null} if no text is required 1069 * after the one-time password. 1070 * @param compactTextBeforeOTP The text (if any) that should appear 1071 * before the generated one-time password 1072 * in the message delivered to the user 1073 * via a delivery mechanism that imposes 1074 * significant constraints on message 1075 * size. This may be {@code null} if no 1076 * text is required before the one-time 1077 * password. 1078 * @param compactTextAfterOTP The text (if any) that should appear 1079 * after the generated one-time password 1080 * in the message delivered to the user 1081 * via a delivery mechanism that imposes 1082 * significant constraints on message 1083 * size. This may be {@code null} if no 1084 * text is required after the one-time 1085 * password. 1086 * @param preferredDeliveryMechanisms An optional ordered list of preferred 1087 * delivery mechanisms that should be 1088 * used to deliver the one-time password 1089 * to the user. It may be {@code null} 1090 * or empty to allow the server to select 1091 * an appropriate delivery mechanism. If 1092 * it is non-{@code null} and non-empty, 1093 * then only the listed mechanisms will 1094 * be considered for use, even if the 1095 * server supports alternate mechanisms 1096 * not included in this list. Each 1097 * {@code ObjectPair} item must have 1098 * a non-{@code null} value for the first 1099 * element, which is the name of the 1100 * target delivery mechanism. It may 1101 * optionally have a non-{@code null} 1102 * value for the second element, which is 1103 * a recipient ID to use for that 1104 * mechanism (e.g., the target mobile 1105 * phone number for SMS delivery, an 1106 * email address for email delivery, 1107 * etc.). If no recipient ID is provided 1108 * for a mechanism, then the server will 1109 * attempt to select a value for the 1110 * user. 1111 * 1112 * @return An ASN.1 octet string suitable for use as the value of this 1113 * extended request. 1114 */ 1115 private static ASN1OctetString encodeValue(final String authenticationID, 1116 final ASN1OctetString staticPassword, final String messageSubject, 1117 final String fullTextBeforeOTP, final String fullTextAfterOTP, 1118 final String compactTextBeforeOTP, final String compactTextAfterOTP, 1119 final List<ObjectPair<String,String>> preferredDeliveryMechanisms) 1120 { 1121 final ArrayList<ASN1Element> elements = new ArrayList<>(8); 1122 1123 elements.add(new ASN1OctetString(TYPE_AUTHN_ID, authenticationID)); 1124 1125 if (staticPassword != null) 1126 { 1127 elements.add(staticPassword); 1128 } 1129 1130 if (messageSubject != null) 1131 { 1132 elements.add(new ASN1OctetString(MESSAGE_SUBJECT_BER_TYPE, 1133 messageSubject)); 1134 } 1135 1136 if (fullTextBeforeOTP != null) 1137 { 1138 elements.add(new ASN1OctetString(FULL_TEXT_BEFORE_OTP_BER_TYPE, 1139 fullTextBeforeOTP)); 1140 } 1141 1142 if (fullTextAfterOTP != null) 1143 { 1144 elements.add(new ASN1OctetString(FULL_TEXT_AFTER_OTP_BER_TYPE, 1145 fullTextAfterOTP)); 1146 } 1147 1148 if (compactTextBeforeOTP != null) 1149 { 1150 elements.add(new ASN1OctetString(COMPACT_TEXT_BEFORE_OTP_BER_TYPE, 1151 compactTextBeforeOTP)); 1152 } 1153 1154 if (compactTextAfterOTP != null) 1155 { 1156 elements.add(new ASN1OctetString(COMPACT_TEXT_AFTER_OTP_BER_TYPE, 1157 compactTextAfterOTP)); 1158 } 1159 1160 if ((preferredDeliveryMechanisms != null) && 1161 (! preferredDeliveryMechanisms.isEmpty())) 1162 { 1163 final ArrayList<ASN1Element> pdmElements = 1164 new ArrayList<>(preferredDeliveryMechanisms.size()); 1165 for (final ObjectPair<String,String> p : preferredDeliveryMechanisms) 1166 { 1167 if (p.getSecond() == null) 1168 { 1169 pdmElements.add(new ASN1Sequence( 1170 new ASN1OctetString(p.getFirst()))); 1171 } 1172 else 1173 { 1174 pdmElements.add(new ASN1Sequence( 1175 new ASN1OctetString(p.getFirst()), 1176 new ASN1OctetString(p.getSecond()))); 1177 } 1178 } 1179 1180 elements.add(new ASN1Sequence( 1181 TYPE_PREFERRED_DELIVERY_MECHANISM_NAMES_AND_IDS, pdmElements)); 1182 } 1183 1184 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 1185 } 1186 1187 1188 1189 /** 1190 * Retrieves the authentication ID for the user to whom the one-time password 1191 * should be delivered. 1192 * 1193 * @return The authentication ID for the user to whom the one-time password 1194 * should be delivered. 1195 */ 1196 public String getAuthenticationID() 1197 { 1198 return authenticationID; 1199 } 1200 1201 1202 1203 /** 1204 * Retrieves the static password for the user to whom the one-time password 1205 * should be delivered. The returned password may be {@code null} if no 1206 * 1207 * 1208 * @return The static password for the user to whom the one-time password 1209 * should be delivered, or {@code null} if no static password should 1210 * be included in the request. 1211 */ 1212 public ASN1OctetString getStaticPassword() 1213 { 1214 return staticPassword; 1215 } 1216 1217 1218 1219 /** 1220 * Retrieves an ordered list of the names of the preferred delivery mechanisms 1221 * for the one-time password, if provided. 1222 * 1223 * @return An ordered list of the names of the preferred delivery mechanisms 1224 * for the one-time password, or {@code null} if this was not 1225 * provided. 1226 */ 1227 public List<String> getPreferredDeliveryMechanisms() 1228 { 1229 if (preferredDeliveryMechanisms.isEmpty()) 1230 { 1231 return null; 1232 } 1233 else 1234 { 1235 final LinkedHashSet<String> s = new LinkedHashSet<>( 1236 StaticUtils.computeMapCapacity(preferredDeliveryMechanisms.size())); 1237 for (final ObjectPair<String,String> p : preferredDeliveryMechanisms) 1238 { 1239 s.add(p.getFirst()); 1240 } 1241 1242 return Collections.unmodifiableList(new ArrayList<>(s)); 1243 } 1244 } 1245 1246 1247 1248 /** 1249 * Retrieves an ordered list of the preferred delivery mechanisms that should 1250 * be used to provide the one-time password to the user, optionally paired 1251 * with a mechanism-specific recipient ID (e.g., a mobile phone number for SMS 1252 * delivery, or an email address for email delivery) that can be used in the 1253 * delivery. If this list is non-empty, then the server will use the first 1254 * mechanism in the list that the server supports and is available for the 1255 * target user, and the server will only consider mechanisms in the provided 1256 * list even if the server supports alternate mechanisms that are not 1257 * included. If this list is empty, then the server will attempt to select an 1258 * appropriate delivery mechanism for the user. 1259 * 1260 * @return An ordered list of the preferred delivery mechanisms for the 1261 * one-time password, or an empty list if none were provided. 1262 */ 1263 public List<ObjectPair<String,String>> 1264 getPreferredDeliveryMechanismNamesAndIDs() 1265 { 1266 return preferredDeliveryMechanisms; 1267 } 1268 1269 1270 1271 /** 1272 * Retrieves the text (if any) that should be used as the message subject for 1273 * delivery mechanisms that can make use of a subject. 1274 * 1275 * @return The text that should be used as the message subject for delivery 1276 * mechanisms that can make use of a subject, or {@code null} if no 1277 * subject should be used, or if the delivery mechanism should 1278 * attempt to automatically determine a subject. 1279 */ 1280 public String getMessageSubject() 1281 { 1282 return messageSubject; 1283 } 1284 1285 1286 1287 /** 1288 * Retrieves the text (if any) that should appear before the one-time password 1289 * in the message delivered to the user via a mechanism that does not impose 1290 * significant constraints on message size. 1291 * 1292 * @return The text that should appear before the one-time password in the 1293 * message delivered to the user via a mechanism that does not impose 1294 * significant constraints on message size, or {@code null} if there 1295 * should not be any text before the one-time password. 1296 */ 1297 public String getFullTextBeforeOTP() 1298 { 1299 return fullTextBeforeOTP; 1300 } 1301 1302 1303 1304 /** 1305 * Retrieves the text (if any) that should appear after the one-time password 1306 * in the message delivered to the user via a mechanism that does not impose 1307 * significant constraints on message size. 1308 * 1309 * @return The text that should appear after the one-time password in the 1310 * message delivered to the user via a mechanism that does not impose 1311 * significant constraints on message size, or {@code null} if there 1312 * should not be any text after the one-time password. 1313 */ 1314 public String getFullTextAfterOTP() 1315 { 1316 return fullTextAfterOTP; 1317 } 1318 1319 1320 1321 /** 1322 * Retrieves the text (if any) that should appear before the one-time password 1323 * in the message delivered to the user via a mechanism that imposes 1324 * significant constraints on message size. 1325 * 1326 * @return The text that should appear before the one-time password in the 1327 * message delivered to the user via a mechanism that imposes 1328 * significant constraints on message size, or {@code null} if there 1329 * should not be any text before the one-time password. 1330 */ 1331 public String getCompactTextBeforeOTP() 1332 { 1333 return compactTextBeforeOTP; 1334 } 1335 1336 1337 1338 /** 1339 * Retrieves the text (if any) that should appear after the one-time password 1340 * in the message delivered to the user via a mechanism that imposes 1341 * significant constraints on message size. 1342 * 1343 * @return The text that should appear after the one-time password in the 1344 * message delivered to the user via a mechanism that imposes 1345 * significant constraints on message size, or {@code null} if there 1346 * should not be any text after the one-time password. 1347 */ 1348 public String getCompactTextAfterOTP() 1349 { 1350 return compactTextAfterOTP; 1351 } 1352 1353 1354 1355 /** 1356 * {@inheritDoc} 1357 */ 1358 @Override() 1359 public DeliverOneTimePasswordExtendedResult process( 1360 final LDAPConnection connection, final int depth) 1361 throws LDAPException 1362 { 1363 final ExtendedResult extendedResponse = super.process(connection, depth); 1364 return new DeliverOneTimePasswordExtendedResult(extendedResponse); 1365 } 1366 1367 1368 1369 /** 1370 * {@inheritDoc}. 1371 */ 1372 @Override() 1373 public DeliverOneTimePasswordExtendedRequest duplicate() 1374 { 1375 return duplicate(getControls()); 1376 } 1377 1378 1379 1380 /** 1381 * {@inheritDoc}. 1382 */ 1383 @Override() 1384 public DeliverOneTimePasswordExtendedRequest duplicate( 1385 final Control[] controls) 1386 { 1387 final DeliverOneTimePasswordExtendedRequest r = 1388 new DeliverOneTimePasswordExtendedRequest(authenticationID, 1389 staticPassword, messageSubject, fullTextBeforeOTP, 1390 fullTextAfterOTP, compactTextBeforeOTP, compactTextAfterOTP, 1391 preferredDeliveryMechanisms, controls); 1392 r.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 1393 return r; 1394 } 1395 1396 1397 1398 /** 1399 * {@inheritDoc} 1400 */ 1401 @Override() 1402 public String getExtendedRequestName() 1403 { 1404 return INFO_DELIVER_OTP_REQ_NAME.get(); 1405 } 1406 1407 1408 1409 /** 1410 * {@inheritDoc} 1411 */ 1412 @Override() 1413 public void toString(final StringBuilder buffer) 1414 { 1415 buffer.append("DeliverOneTimePasswordExtendedRequest(authenticationID="); 1416 buffer.append(authenticationID); 1417 1418 if (messageSubject != null) 1419 { 1420 buffer.append(", messageSubject='"); 1421 buffer.append(messageSubject); 1422 buffer.append('\''); 1423 } 1424 1425 if (fullTextBeforeOTP != null) 1426 { 1427 buffer.append(", fullTextBeforeOTP='"); 1428 buffer.append(fullTextBeforeOTP); 1429 buffer.append('\''); 1430 } 1431 1432 if (fullTextAfterOTP != null) 1433 { 1434 buffer.append(", fullTextAfterOTP='"); 1435 buffer.append(fullTextAfterOTP); 1436 buffer.append('\''); 1437 } 1438 1439 if (compactTextBeforeOTP != null) 1440 { 1441 buffer.append(", compactTextBeforeOTP='"); 1442 buffer.append(compactTextBeforeOTP); 1443 buffer.append('\''); 1444 } 1445 1446 if (compactTextAfterOTP != null) 1447 { 1448 buffer.append(", compactTextAfterOTP='"); 1449 buffer.append(compactTextAfterOTP); 1450 buffer.append('\''); 1451 } 1452 1453 if (preferredDeliveryMechanisms != null) 1454 { 1455 buffer.append(", preferredDeliveryMechanisms={"); 1456 1457 final Iterator<ObjectPair<String,String>> iterator = 1458 preferredDeliveryMechanisms.iterator(); 1459 while (iterator.hasNext()) 1460 { 1461 final ObjectPair<String,String> p = iterator.next(); 1462 buffer.append('\''); 1463 buffer.append(p.getFirst()); 1464 if (p.getSecond() != null) 1465 { 1466 buffer.append('('); 1467 buffer.append(p.getSecond()); 1468 buffer.append(')'); 1469 } 1470 buffer.append('\''); 1471 if (iterator.hasNext()) 1472 { 1473 buffer.append(','); 1474 } 1475 } 1476 } 1477 1478 final Control[] controls = getControls(); 1479 if (controls.length > 0) 1480 { 1481 buffer.append(", controls={"); 1482 for (int i=0; i < controls.length; i++) 1483 { 1484 if (i > 0) 1485 { 1486 buffer.append(", "); 1487 } 1488 1489 buffer.append(controls[i]); 1490 } 1491 buffer.append('}'); 1492 } 1493 1494 buffer.append(')'); 1495 } 1496}