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