001/* 002 * Copyright 2015-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-2019 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk.unboundidds.extensions; 022 023 024 025import java.util.ArrayList; 026import java.util.Collections; 027import java.util.Iterator; 028import java.util.List; 029 030import com.unboundid.asn1.ASN1Boolean; 031import com.unboundid.asn1.ASN1Element; 032import com.unboundid.asn1.ASN1Long; 033import com.unboundid.asn1.ASN1OctetString; 034import com.unboundid.asn1.ASN1Sequence; 035import com.unboundid.ldap.sdk.Control; 036import com.unboundid.ldap.sdk.ExtendedRequest; 037import com.unboundid.ldap.sdk.ExtendedResult; 038import com.unboundid.ldap.sdk.LDAPConnection; 039import com.unboundid.ldap.sdk.LDAPException; 040import com.unboundid.ldap.sdk.ResultCode; 041import com.unboundid.util.Debug; 042import com.unboundid.util.NotMutable; 043import com.unboundid.util.ObjectPair; 044import com.unboundid.util.StaticUtils; 045import com.unboundid.util.ThreadSafety; 046import com.unboundid.util.ThreadSafetyLevel; 047import com.unboundid.util.Validator; 048 049import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*; 050 051 052 053/** 054 * This class provides an implementation of an extended request that can be used 055 * to trigger the delivery of a temporary single-use token to a specified user 056 * via some out-of-band mechanism. It can be used for security purposes 057 * (e.g., as part of step-up authentication), for data validation purposes 058 * (e.g., to verify that a user can receive e-mail messages at a given address 059 * or SMS messages at a given phone number), or for other purposes in which it 060 * could be useful to deliver and consume a token through some out-of-band 061 * mechanism. 062 * <BR> 063 * <BLOCKQUOTE> 064 * <B>NOTE:</B> This class, and other classes within the 065 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 066 * supported for use against Ping Identity, UnboundID, and 067 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 068 * for proprietary functionality or for external specifications that are not 069 * considered stable or mature enough to be guaranteed to work in an 070 * interoperable way with other types of LDAP servers. 071 * </BLOCKQUOTE> 072 * <BR> 073 * This extended request has an OID of "1.3.6.1.4.1.30221.2.6.49" and it must 074 * have a value with the following encoding: 075 * <PRE> 076 * DeliverSingleUseTokenRequestValue ::= SEQUENCE { 077 * userDN LDAPDN, 078 * tokenID OCTET STRING, 079 * validityDurationMillis [0] INTEGER OPTIONAL, 080 * messageSubject [1] OCTET STRING OPTIONAL, 081 * fullTextBeforeToken [2] OCTET STRING OPTIONAL, 082 * fullTextAfterToken [3] OCTET STRING OPTIONAL, 083 * compactTextBeforeToken [4] OCTET STRING OPTIONAL, 084 * compactTextAfterToken [5] OCTET STRING OPTIONAL, 085 * preferredDeliveryMechanism [6] SEQUENCE OF SEQUENCE { 086 * mechanismName OCTET STRING, 087 * recipientID OCTET STRING OPTIONAL }, 088 * deliverIfPasswordExpired [7] BOOLEAN DEFAULT FALSE, 089 * deliverIfAccountLocked [8] BOOLEAN DEFAULT FALSE, 090 * deliverIfAccountDisabled [9] BOOLEAN DEFAULT FALSE, 091 * deliverIfAccountExpired [10] BOOLEAN DEFAULT FALSE, 092 * ... } 093 * </PRE> 094 * 095 * @see DeliverSingleUseTokenExtendedResult 096 * @see ConsumeSingleUseTokenExtendedRequest 097 */ 098@NotMutable() 099@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 100public final class DeliverSingleUseTokenExtendedRequest 101 extends ExtendedRequest 102{ 103 /** 104 * The OID (1.3.6.1.4.1.30221.2.6.49) for the deliver single-use token 105 * extended request. 106 */ 107 public static final String DELIVER_SINGLE_USE_TOKEN_REQUEST_OID = 108 "1.3.6.1.4.1.30221.2.6.49"; 109 110 111 112 /** 113 * The BER type for the "validity duration millis" element of the value 114 * sequence. 115 */ 116 private static final byte VALIDITY_DURATION_MILLIS_BER_TYPE = (byte) 0x80; 117 118 119 120 /** 121 * The BER type for the "message subject" element of the value sequence. 122 */ 123 private static final byte MESSAGE_SUBJECT_BER_TYPE = (byte) 0x81; 124 125 126 127 /** 128 * The BER type for the "full text before token" element of the value 129 * sequence. 130 */ 131 private static final byte FULL_TEXT_BEFORE_TOKEN_BER_TYPE = (byte) 0x82; 132 133 134 135 /** 136 * The BER type for the "full text after token" element of the value 137 * sequence. 138 */ 139 private static final byte FULL_TEXT_AFTER_TOKEN_BER_TYPE = (byte) 0x83; 140 141 142 143 /** 144 * The BER type for the "compact text before token" element of the value 145 * sequence. 146 */ 147 private static final byte COMPACT_TEXT_BEFORE_TOKEN_BER_TYPE = (byte) 0x84; 148 149 150 151 /** 152 * The BER type for the "compact text after token" element of the value 153 * sequence. 154 */ 155 private static final byte COMPACT_TEXT_AFTER_TOKEN_BER_TYPE = (byte) 0x85; 156 157 158 159 /** 160 * The BER type for the "preferred delivery mechanism" element of the value 161 * sequence. 162 */ 163 private static final byte PREFERRED_DELIVERY_MECHANISM_BER_TYPE = (byte) 0xA6; 164 165 166 167 /** 168 * The BER type for the "deliver if password expired" element of the value 169 * sequence. 170 */ 171 private static final byte DELIVER_IF_PASSWORD_EXPIRED_TYPE = (byte) 0x87; 172 173 174 175 /** 176 * The BER type for the "deliver if account locked" element of the value 177 * sequence. 178 */ 179 private static final byte DELIVER_IF_ACCOUNT_LOCKED_TYPE = (byte) 0x88; 180 181 182 183 /** 184 * The BER type for the "deliver if account disabled" element of the value 185 * sequence. 186 */ 187 private static final byte DELIVER_IF_ACCOUNT_DISABLED_TYPE = (byte) 0x89; 188 189 190 191 /** 192 * The BER type for the "deliver if account expired" element of the value 193 * sequence. 194 */ 195 private static final byte DELIVER_IF_ACCOUNT_EXPIRED_TYPE = (byte) 0x8A; 196 197 198 199 /** 200 * The serial version UID for this serializable class. 201 */ 202 private static final long serialVersionUID = -4158226639899928825L; 203 204 205 206 // Indicates whether the server should attempt to deliver the token if the 207 // target user's account has been administratively disabled. 208 private final boolean deliverIfAccountDisabled; 209 210 // Indicates whether the server should attempt to deliver the token if the 211 // target user's account has expired. 212 private final boolean deliverIfAccountExpired; 213 214 // Indicates whether the server should attempt to deliver the token if the 215 // target user's account has been locked for some reason. 216 private final boolean deliverIfAccountLocked; 217 218 // Indicates whether the server should attempt to deliver the token if the 219 // target user's password is expired. 220 private final boolean deliverIfPasswordExpired; 221 222 // An optional list of the preferred delivery mechanisms that should be used. 223 private final List<ObjectPair<String,String>> preferredDeliveryMechanisms; 224 225 // The maximum length of time, in milliseconds, that the token should be 226 // considered valid. 227 private final Long validityDurationMillis; 228 229 // The text to include after the token in a compact message. 230 private final String compactTextAfterToken; 231 232 // The text to include before the token in a compact message. 233 private final String compactTextBeforeToken; 234 235 // The text to include after the token in a message without size constraints. 236 private final String fullTextAfterToken; 237 238 // The text to include before the token in a message without size constraints. 239 private final String fullTextBeforeToken; 240 241 // The text to use as the message subject. 242 private final String messageSubject; 243 244 // The identifier that will be used when consuming this token. 245 private final String tokenID; 246 247 // The DN of the user for whom the token should be generated and delivered. 248 private final String userDN; 249 250 251 252 /** 253 * Creates a new deliver single-use token extended request with the provided 254 * information. 255 * 256 * @param userDN The DN of the user for whom the token 257 * should be generated and delivered. It 258 * must not be {@code null}. 259 * @param tokenID An identifier for the token, which can 260 * differentiate between separate uses of 261 * this extended operation for different 262 * purposes. This token ID should be 263 * provided in the request to consume the 264 * token that has been delivered. It 265 * must not be {@code null}. 266 * @param validityDurationMillis The maximum length of time in 267 * milliseconds that the generated token 268 * should be considered valid. It may be 269 * {@code null} if the server should 270 * determine the token validity duration. 271 * If it is non-{@code null}, then the 272 * value must be greater than zero. 273 * @param messageSubject The text (if any) that should be used 274 * as the message subject if the delivery 275 * mechanism accepts a subject. This may 276 * be {@code null} if no subject is 277 * required or a subject should be 278 * automatically generated. 279 * @param fullTextBeforeToken The text (if any) that should appear 280 * before the generated single-use token 281 * in the message delivered to the user 282 * via a delivery mechanism that does not 283 * impose significant constraints on 284 * message size. This may be 285 * {@code null} if no text is required 286 * before the token. 287 * @param fullTextAfterToken The text (if any) that should appear 288 * after the generated single-use token 289 * in the message delivered to the user 290 * via a delivery mechanism that does not 291 * impose significant constraints on 292 * message size. This may be 293 * {@code null} if no text is required 294 * after the token. 295 * @param compactTextBeforeToken The text (if any) that should appear 296 * before the generated single-use token 297 * in the message delivered to the user 298 * via a delivery mechanism that imposes 299 * significant constraints on message 300 * size. This may be {@code null} if no 301 * text is required before the token. 302 * @param compactTextAfterToken The text (if any) that should appear 303 * after the generated single-use token 304 * in the message delivered to the user 305 * via a delivery mechanism that imposes 306 * significant constraints on message 307 * size. This may be {@code null} if no 308 * text is required after the token. 309 * @param preferredDeliveryMechanisms An optional list of the preferred 310 * delivery mechanisms that should be 311 * used to convey the token to the target 312 * user. It may be {@code null} or empty 313 * if the server should determine the 314 * delivery mechanisms to attempt. If 315 * a list of preferred delivery 316 * mechanisms is provided, the server 317 * will only attempt to deliver the token 318 * through these mechanisms, with 319 * attempts made in the order specified 320 * in this list. 321 * @param deliverIfPasswordExpired Indicates whether to generate and 322 * deliver a token if the target user's 323 * password is expired. 324 * @param deliverIfAccountLocked Indicates whether to generate and 325 * deliver a token if the target user's 326 * account is locked for some reason 327 * (e.g., too many failed authentication 328 * attempts, the account has been idle 329 * for too long, the user failed to 330 * change his/her password in a timely 331 * manner after an administrative reset, 332 * etc.). 333 * @param deliverIfAccountDisabled Indicates whether to generate and 334 * deliver a token if the target user's 335 * account has been disabled by an 336 * administrator. 337 * @param deliverIfAccountExpired Indicates whether to generate and 338 * deliver a token if the target user's 339 * account has expired. 340 * @param controls An optional set of controls to include 341 * in the request. It may be 342 * {@code null} or empty if no controls 343 * are required. 344 */ 345 public DeliverSingleUseTokenExtendedRequest(final String userDN, 346 final String tokenID, final Long validityDurationMillis, 347 final String messageSubject, final String fullTextBeforeToken, 348 final String fullTextAfterToken, 349 final String compactTextBeforeToken, 350 final String compactTextAfterToken, 351 final List<ObjectPair<String,String>> preferredDeliveryMechanisms, 352 final boolean deliverIfPasswordExpired, 353 final boolean deliverIfAccountLocked, 354 final boolean deliverIfAccountDisabled, 355 final boolean deliverIfAccountExpired, final Control... controls) 356 { 357 super(DELIVER_SINGLE_USE_TOKEN_REQUEST_OID, 358 encodeValue(userDN, tokenID, validityDurationMillis, messageSubject, 359 fullTextBeforeToken, fullTextAfterToken, compactTextBeforeToken, 360 compactTextAfterToken, preferredDeliveryMechanisms, 361 deliverIfPasswordExpired, deliverIfAccountLocked, 362 deliverIfAccountDisabled, deliverIfAccountExpired), 363 controls); 364 365 this.userDN = userDN; 366 this.tokenID = tokenID; 367 this.validityDurationMillis = validityDurationMillis; 368 this.messageSubject = messageSubject; 369 this.fullTextBeforeToken = fullTextBeforeToken; 370 this.fullTextAfterToken = fullTextAfterToken; 371 this.compactTextBeforeToken = compactTextBeforeToken; 372 this.compactTextAfterToken = compactTextAfterToken; 373 this.deliverIfPasswordExpired = deliverIfPasswordExpired; 374 this.deliverIfAccountLocked = deliverIfAccountLocked; 375 this.deliverIfAccountDisabled = deliverIfAccountDisabled; 376 this.deliverIfAccountExpired = deliverIfAccountExpired; 377 378 if (preferredDeliveryMechanisms == null) 379 { 380 this.preferredDeliveryMechanisms = Collections.emptyList(); 381 } 382 else 383 { 384 this.preferredDeliveryMechanisms = Collections.unmodifiableList( 385 new ArrayList<>(preferredDeliveryMechanisms)); 386 } 387 } 388 389 390 391 /** 392 * Decodes the provided extended request as a deliver single-use token 393 * extended request. 394 * 395 * @param request The extended request to decode as a deliver single-use 396 * token extended request. 397 * 398 * @throws LDAPException If the provided extended request cannot be decoded 399 * as a deliver single-use token request. 400 */ 401 public DeliverSingleUseTokenExtendedRequest(final ExtendedRequest request) 402 throws LDAPException 403 { 404 super(request); 405 406 final ASN1OctetString value = request.getValue(); 407 if (value == null) 408 { 409 throw new LDAPException(ResultCode.DECODING_ERROR, 410 ERR_DELIVER_SINGLE_USE_TOKEN_REQUEST_NO_VALUE.get()); 411 } 412 413 try 414 { 415 final ASN1Element[] elements = 416 ASN1Sequence.decodeAsSequence(value.getValue()).elements(); 417 userDN = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue(); 418 tokenID = ASN1OctetString.decodeAsOctetString(elements[1]).stringValue(); 419 420 Long validityDuration = null; 421 String subject = null; 422 String fullBefore = null; 423 String fullAfter = null; 424 String compactBefore = null; 425 String compactAfter = null; 426 final ArrayList<ObjectPair<String,String>> pdmList = new ArrayList<>(10); 427 boolean ifPasswordExpired = false; 428 boolean ifAccountLocked = false; 429 boolean ifAccountDisabled = false; 430 boolean ifAccountExpired = false; 431 for (int i=2; i < elements.length; i++) 432 { 433 switch (elements[i].getType()) 434 { 435 case VALIDITY_DURATION_MILLIS_BER_TYPE: 436 validityDuration = ASN1Long.decodeAsLong(elements[i]).longValue(); 437 break; 438 439 case MESSAGE_SUBJECT_BER_TYPE: 440 subject = 441 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue(); 442 break; 443 444 case FULL_TEXT_BEFORE_TOKEN_BER_TYPE: 445 fullBefore = 446 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue(); 447 break; 448 449 case FULL_TEXT_AFTER_TOKEN_BER_TYPE: 450 fullAfter = 451 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue(); 452 break; 453 454 case COMPACT_TEXT_BEFORE_TOKEN_BER_TYPE: 455 compactBefore = 456 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue(); 457 break; 458 459 case COMPACT_TEXT_AFTER_TOKEN_BER_TYPE: 460 compactAfter = 461 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue(); 462 break; 463 464 case PREFERRED_DELIVERY_MECHANISM_BER_TYPE: 465 for (final ASN1Element pdmElement : 466 ASN1Sequence.decodeAsSequence(elements[i]).elements()) 467 { 468 final ASN1Element[] dmElements = 469 ASN1Sequence.decodeAsSequence(pdmElement).elements(); 470 final String name = ASN1OctetString.decodeAsOctetString( 471 dmElements[0]).stringValue(); 472 473 final String recipientID; 474 if (dmElements.length > 1) 475 { 476 recipientID = ASN1OctetString.decodeAsOctetString( 477 dmElements[1]).stringValue(); 478 } 479 else 480 { 481 recipientID = null; 482 } 483 pdmList.add(new ObjectPair<>(name, recipientID)); 484 } 485 break; 486 487 case DELIVER_IF_PASSWORD_EXPIRED_TYPE: 488 ifPasswordExpired = 489 ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue(); 490 break; 491 492 case DELIVER_IF_ACCOUNT_LOCKED_TYPE: 493 ifAccountLocked = 494 ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue(); 495 break; 496 497 case DELIVER_IF_ACCOUNT_DISABLED_TYPE: 498 ifAccountDisabled = 499 ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue(); 500 break; 501 502 case DELIVER_IF_ACCOUNT_EXPIRED_TYPE: 503 ifAccountExpired = 504 ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue(); 505 break; 506 507 default: 508 throw new LDAPException(ResultCode.DECODING_ERROR, 509 ERR_DELIVER_SINGLE_USE_TOKEN_REQUEST_UNKNOWN_ELEMENT.get( 510 StaticUtils.toHex(elements[i].getType()))); 511 } 512 } 513 514 validityDurationMillis = validityDuration; 515 messageSubject = subject; 516 fullTextBeforeToken = fullBefore; 517 fullTextAfterToken = fullAfter; 518 compactTextBeforeToken = compactBefore; 519 compactTextAfterToken = compactAfter; 520 preferredDeliveryMechanisms = Collections.unmodifiableList(pdmList); 521 deliverIfPasswordExpired = ifPasswordExpired; 522 deliverIfAccountLocked = ifAccountLocked; 523 deliverIfAccountDisabled = ifAccountDisabled; 524 deliverIfAccountExpired = ifAccountExpired; 525 } 526 catch (final LDAPException le) 527 { 528 Debug.debugException(le); 529 throw le; 530 } 531 catch (final Exception e) 532 { 533 Debug.debugException(e); 534 throw new LDAPException(ResultCode.DECODING_ERROR, 535 ERR_DELIVER_SINGLE_USE_TOKEN_REQUEST_CANNOT_DECODE.get( 536 StaticUtils.getExceptionMessage(e)), 537 e); 538 } 539 } 540 541 542 543 /** 544 * Encodes the provided information into an ASN.1 octet string suitable for 545 * use as the value of the extended request. 546 * 547 * @param userDN The DN of the user for whom the token 548 * should be generated and delivered. It 549 * must not be {@code null}. 550 * @param tokenID An identifier for the token, which can 551 * differentiate between separate uses of 552 * this extended operation for different 553 * purposes. This token ID should be 554 * provided in the request to consume the 555 * token that has been delivered. It 556 * must not be {@code null}. 557 * @param validityDurationMillis The maximum length of time in 558 * milliseconds that the generated token 559 * should be considered valid. It may be 560 * {@code null} if the server should 561 * determine the token validity duration. 562 * If it is non-{@code null}, then the 563 * value must be greater than zero. 564 * @param messageSubject The text (if any) that should be used 565 * as the message subject if the delivery 566 * mechanism accepts a subject. This may 567 * be {@code null} if no subject is 568 * required or a subject should be 569 * automatically generated. 570 * @param fullTextBeforeToken The text (if any) that should appear 571 * before the generated single-use token 572 * in the message delivered to the user 573 * via a delivery mechanism that does not 574 * impose significant constraints on 575 * message size. This may be 576 * {@code null} if no text is required 577 * before the token. 578 * @param fullTextAfterToken The text (if any) that should appear 579 * after the generated single-use token 580 * in the message delivered to the user 581 * via a delivery mechanism that does not 582 * impose significant constraints on 583 * message size. This may be 584 * {@code null} if no text is required 585 * after the token. 586 * @param compactTextBeforeToken The text (if any) that should appear 587 * before the generated single-use token 588 * in the message delivered to the user 589 * via a delivery mechanism that imposes 590 * significant constraints on message 591 * size. This may be {@code null} if no 592 * text is required before the token. 593 * @param compactTextAfterToken The text (if any) that should appear 594 * after the generated single-use token 595 * in the message delivered to the user 596 * via a delivery mechanism that imposes 597 * significant constraints on message 598 * size. This may be {@code null} if no 599 * text is required after the token. 600 * @param preferredDeliveryMechanisms An optional list of the preferred 601 * delivery mechanisms that should be 602 * used to convey the token to the target 603 * user. It may be {@code null} or empty 604 * if the server should determine the 605 * delivery mechanisms to attempt. If 606 * a list of preferred delivery 607 * mechanisms is provided, the server 608 * will only attempt to deliver the token 609 * through these mechanisms, with 610 * attempts made in the order specified 611 * in this list. 612 * @param deliverIfPasswordExpired Indicates whether to generate and 613 * deliver a token if the target user's 614 * password is expired. 615 * @param deliverIfAccountLocked Indicates whether to generate and 616 * deliver a token if the target user's 617 * account is locked for some reason 618 * (e.g., too many failed authentication 619 * attempts, the account has been idle 620 * for too long, the user failed to 621 * change his/her password in a timely 622 * manner after an administrative reset, 623 * etc.). 624 * @param deliverIfAccountDisabled Indicates whether to generate and 625 * deliver a token if the target user's 626 * account has been disabled by an 627 * administrator. 628 * @param deliverIfAccountExpired Indicates whether to generate and 629 * deliver a token if the target user's 630 * account has expired. 631 * 632 * @return An ASN.1 octet string containing the encoded value. 633 */ 634 private static ASN1OctetString encodeValue(final String userDN, 635 final String tokenID, final Long validityDurationMillis, 636 final String messageSubject, final String fullTextBeforeToken, 637 final String fullTextAfterToken, final String compactTextBeforeToken, 638 final String compactTextAfterToken, 639 final List<ObjectPair<String,String>> preferredDeliveryMechanisms, 640 final boolean deliverIfPasswordExpired, 641 final boolean deliverIfAccountLocked, 642 final boolean deliverIfAccountDisabled, 643 final boolean deliverIfAccountExpired) 644 { 645 Validator.ensureNotNull(userDN); 646 Validator.ensureNotNull(tokenID); 647 648 if (validityDurationMillis != null) 649 { 650 Validator.ensureTrue(validityDurationMillis > 0L); 651 } 652 653 654 final ArrayList<ASN1Element> elements = new ArrayList<>(13); 655 elements.add(new ASN1OctetString(userDN)); 656 elements.add(new ASN1OctetString(tokenID)); 657 658 if (validityDurationMillis != null) 659 { 660 elements.add(new ASN1Long(VALIDITY_DURATION_MILLIS_BER_TYPE, 661 validityDurationMillis)); 662 } 663 664 if (messageSubject != null) 665 { 666 elements.add(new ASN1OctetString(MESSAGE_SUBJECT_BER_TYPE, 667 messageSubject)); 668 } 669 670 if (fullTextBeforeToken != null) 671 { 672 elements.add(new ASN1OctetString(FULL_TEXT_BEFORE_TOKEN_BER_TYPE, 673 fullTextBeforeToken)); 674 } 675 676 if (fullTextAfterToken != null) 677 { 678 elements.add(new ASN1OctetString(FULL_TEXT_AFTER_TOKEN_BER_TYPE, 679 fullTextAfterToken)); 680 } 681 682 if (compactTextBeforeToken != null) 683 { 684 elements.add(new ASN1OctetString(COMPACT_TEXT_BEFORE_TOKEN_BER_TYPE, 685 compactTextBeforeToken)); 686 } 687 688 if (compactTextAfterToken != null) 689 { 690 elements.add(new ASN1OctetString(COMPACT_TEXT_AFTER_TOKEN_BER_TYPE, 691 compactTextAfterToken)); 692 } 693 694 if ((preferredDeliveryMechanisms != null) && 695 (! preferredDeliveryMechanisms.isEmpty())) 696 { 697 final ArrayList<ASN1Element> pdmElements = 698 new ArrayList<>(preferredDeliveryMechanisms.size()); 699 for (final ObjectPair<String,String> p : preferredDeliveryMechanisms) 700 { 701 final ArrayList<ASN1Element> l = new ArrayList<>(2); 702 l.add(new ASN1OctetString(p.getFirst())); 703 if (p.getSecond() != null) 704 { 705 l.add(new ASN1OctetString(p.getSecond())); 706 } 707 pdmElements.add(new ASN1Sequence(l)); 708 } 709 elements.add(new ASN1Sequence(PREFERRED_DELIVERY_MECHANISM_BER_TYPE, 710 pdmElements)); 711 } 712 713 if (deliverIfPasswordExpired) 714 { 715 elements.add(new ASN1Boolean(DELIVER_IF_PASSWORD_EXPIRED_TYPE, true)); 716 } 717 718 if (deliverIfAccountLocked) 719 { 720 elements.add(new ASN1Boolean(DELIVER_IF_ACCOUNT_LOCKED_TYPE, true)); 721 } 722 723 if (deliverIfAccountDisabled) 724 { 725 elements.add(new ASN1Boolean(DELIVER_IF_ACCOUNT_DISABLED_TYPE, true)); 726 } 727 728 if (deliverIfAccountExpired) 729 { 730 elements.add(new ASN1Boolean(DELIVER_IF_ACCOUNT_EXPIRED_TYPE, true)); 731 } 732 733 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 734 } 735 736 737 738 /** 739 * Retrieves the DN of the user for whom the token should be generated and 740 * delivered. 741 * 742 * @return The DN of the user for whom the token should be generated and 743 * delivered. 744 */ 745 public String getUserDN() 746 { 747 return userDN; 748 } 749 750 751 752 /** 753 * Retrieves an identifier for the token, which can differentiate between 754 * separate uses of this extended operation for different purposes, and should 755 * be provided when consuming the token via the 756 * {@link ConsumeSingleUseTokenExtendedRequest}. 757 * 758 * @return An identifier for the token. 759 */ 760 public String getTokenID() 761 { 762 return tokenID; 763 } 764 765 766 767 /** 768 * Retrieves the maximum length of time in milliseconds that the generated 769 * token should be considered valid, if defined. An attempt to consume the 770 * token after this length of time has elapsed will fail. 771 * 772 * @return The maximum length of time in milliseconds that the generated 773 * token should be considered valid, or {@code null} if the client 774 * did not specify a value and the token validity duration will be 775 * determined by the server. 776 */ 777 public Long getValidityDurationMillis() 778 { 779 return validityDurationMillis; 780 } 781 782 783 784 /** 785 * Retrieves the text (if any) that should be used as the message subject for 786 * delivery mechanisms that can make use of a subject. 787 * 788 * @return The text that should be used as the message subject for delivery 789 * mechanisms that can make use of a subject, or {@code null} if no 790 * subject should be used, or if the delivery mechanism should 791 * attempt to automatically determine a subject. 792 */ 793 public String getMessageSubject() 794 { 795 return messageSubject; 796 } 797 798 799 800 /** 801 * Retrieves the text (if any) that should appear before the single-use token 802 * in the message delivered to the user via a mechanism that does not impose 803 * significant constraints on message size. 804 * 805 * @return The text that should appear before the single-use token in the 806 * message delivered to the user via a mechanism that does not impose 807 * significant constraints on message size, or {@code null} if there 808 * should not be any text before the token. 809 */ 810 public String getFullTextBeforeToken() 811 { 812 return fullTextBeforeToken; 813 } 814 815 816 817 /** 818 * Retrieves the text (if any) that should appear after the single-use token 819 * in the message delivered to the user via a mechanism that does not impose 820 * significant constraints on message size. 821 * 822 * @return The text that should appear after the single-use token in the 823 * message delivered to the user via a mechanism that does not impose 824 * significant constraints on message size, or {@code null} if there 825 * should not be any text after the token. 826 */ 827 public String getFullTextAfterToken() 828 { 829 return fullTextAfterToken; 830 } 831 832 833 834 /** 835 * Retrieves the text (if any) that should appear before the single-use token 836 * in the message delivered to the user via a mechanism that imposes 837 * significant constraints on message size. 838 * 839 * @return The text that should appear before the single-use token in the 840 * message delivered to the user via a mechanism that imposes 841 * significant constraints on message size, or {@code null} if there 842 * should not be any text before the token. 843 */ 844 public String getCompactTextBeforeToken() 845 { 846 return compactTextBeforeToken; 847 } 848 849 850 851 /** 852 * Retrieves the text (if any) that should appear after the single-use token 853 * in the message delivered to the user via a mechanism that imposes 854 * significant constraints on message size. 855 * 856 * @return The text that should appear after the single-use token in the 857 * message delivered to the user via a mechanism that imposes 858 * significant constraints on message size, or {@code null} if there 859 * should not be any text after the token. 860 */ 861 public String getCompactTextAfterToken() 862 { 863 return compactTextAfterToken; 864 } 865 866 867 868 /** 869 * Retrieves a list of the preferred delivery mechanisms that should be used 870 * to provide the generated token to the target user. If the returned list is 871 * empty, then the server will attempt to determine which mechanism(s) to use 872 * and in which order to try them. If this list is not empty, then the server 873 * will only attempt the specified mechanisms and in the order in which they 874 * are listed. 875 * 876 * @return A list of the preferred delivery mechanisms that should be used to 877 * provide the generated token to the target user, or an empty list 878 * if the server should determine the delivery mechanisms to attempt. 879 */ 880 public List<ObjectPair<String,String>> getPreferredDeliveryMechanisms() 881 { 882 return preferredDeliveryMechanisms; 883 } 884 885 886 887 /** 888 * Indicates whether to attempt to generate and deliver a token if the 889 * target user's password is expired. 890 * 891 * @return {@code true} if the server should attempt to deliver a token to a 892 * user with an expired password, or {@code false} if not. 893 */ 894 public boolean deliverIfPasswordExpired() 895 { 896 return deliverIfPasswordExpired; 897 } 898 899 900 901 /** 902 * Indicates whether to attempt to generate and deliver a token if the 903 * target user's account is locked for some reason (e.g., because there have 904 * been too many failed authentication attempts, because the account has been 905 * idle for too long, or because the password was not changed soon enough 906 * after an administrative reset). 907 * 908 * @return {@code true} if the server should attempt to deliver a token to a 909 * user with a locked account, or {@code false} if not. 910 */ 911 public boolean deliverIfAccountLocked() 912 { 913 return deliverIfAccountLocked; 914 } 915 916 917 918 /** 919 * Indicates whether to attempt to generate and deliver a token if the 920 * target user's account has been disabled by an administrator. 921 * 922 * @return {@code true} if the server should attempt to deliver a token to a 923 * user with a disabled account, or {@code false} if not. 924 */ 925 public boolean deliverIfAccountDisabled() 926 { 927 return deliverIfAccountDisabled; 928 } 929 930 931 932 /** 933 * Indicates whether to attempt to generate and deliver a token if the 934 * target user's account has expired. 935 * 936 * @return {@code true} if the server should attempt to deliver a token to a 937 * user with an expired account, or {@code false} if not. 938 */ 939 public boolean deliverIfAccountExpired() 940 { 941 return deliverIfAccountExpired; 942 } 943 944 945 946 /** 947 * {@inheritDoc} 948 */ 949 @Override() 950 public DeliverSingleUseTokenExtendedResult process( 951 final LDAPConnection connection, final int depth) 952 throws LDAPException 953 { 954 final ExtendedResult extendedResponse = super.process(connection, depth); 955 return new DeliverSingleUseTokenExtendedResult(extendedResponse); 956 } 957 958 959 960 /** 961 * {@inheritDoc}. 962 */ 963 @Override() 964 public DeliverSingleUseTokenExtendedRequest duplicate() 965 { 966 return duplicate(getControls()); 967 } 968 969 970 971 /** 972 * {@inheritDoc}. 973 */ 974 @Override() 975 public DeliverSingleUseTokenExtendedRequest duplicate( 976 final Control[] controls) 977 { 978 final DeliverSingleUseTokenExtendedRequest r = 979 new DeliverSingleUseTokenExtendedRequest(userDN, tokenID, 980 validityDurationMillis, messageSubject, fullTextBeforeToken, 981 fullTextAfterToken, compactTextBeforeToken, compactTextAfterToken, 982 preferredDeliveryMechanisms, deliverIfPasswordExpired, 983 deliverIfAccountLocked, deliverIfAccountDisabled, 984 deliverIfAccountExpired, controls); 985 r.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 986 return r; 987 } 988 989 990 991 /** 992 * {@inheritDoc} 993 */ 994 @Override() 995 public String getExtendedRequestName() 996 { 997 return INFO_EXTENDED_REQUEST_NAME_DELIVER_SINGLE_USE_TOKEN.get(); 998 } 999 1000 1001 1002 /** 1003 * {@inheritDoc} 1004 */ 1005 @Override() 1006 public void toString(final StringBuilder buffer) 1007 { 1008 buffer.append("DeliverSingleUseTokenExtendedRequest(userDN='"); 1009 buffer.append(userDN); 1010 buffer.append("', tokenID='"); 1011 buffer.append(tokenID); 1012 buffer.append('\''); 1013 1014 if (validityDurationMillis != null) 1015 { 1016 buffer.append(", validityDurationMillis="); 1017 buffer.append(validityDurationMillis); 1018 } 1019 1020 if (messageSubject != null) 1021 { 1022 buffer.append(", messageSubject='"); 1023 buffer.append(messageSubject); 1024 buffer.append('\''); 1025 } 1026 1027 if (fullTextBeforeToken != null) 1028 { 1029 buffer.append(", fullTextBeforeToken='"); 1030 buffer.append(fullTextBeforeToken); 1031 buffer.append('\''); 1032 } 1033 1034 if (fullTextAfterToken != null) 1035 { 1036 buffer.append(", fullTextAfterToken='"); 1037 buffer.append(fullTextAfterToken); 1038 buffer.append('\''); 1039 } 1040 1041 if (compactTextBeforeToken != null) 1042 { 1043 buffer.append(", compactTextBeforeToken='"); 1044 buffer.append(compactTextBeforeToken); 1045 buffer.append('\''); 1046 } 1047 1048 if (compactTextAfterToken != null) 1049 { 1050 buffer.append(", compactTextAfterToken='"); 1051 buffer.append(compactTextAfterToken); 1052 buffer.append('\''); 1053 } 1054 1055 if (preferredDeliveryMechanisms != null) 1056 { 1057 buffer.append(", preferredDeliveryMechanisms={"); 1058 1059 final Iterator<ObjectPair<String,String>> iterator = 1060 preferredDeliveryMechanisms.iterator(); 1061 while (iterator.hasNext()) 1062 { 1063 final ObjectPair<String,String> p = iterator.next(); 1064 buffer.append('\''); 1065 buffer.append(p.getFirst()); 1066 if (p.getSecond() != null) 1067 { 1068 buffer.append('('); 1069 buffer.append(p.getSecond()); 1070 buffer.append(')'); 1071 } 1072 buffer.append('\''); 1073 if (iterator.hasNext()) 1074 { 1075 buffer.append(','); 1076 } 1077 } 1078 } 1079 1080 buffer.append(", deliverIfPasswordExpired="); 1081 buffer.append(deliverIfPasswordExpired); 1082 buffer.append(", deliverIfAccountLocked="); 1083 buffer.append(deliverIfAccountLocked); 1084 buffer.append(", deliverIfAccountDisabled="); 1085 buffer.append(deliverIfAccountDisabled); 1086 buffer.append(", deliverIfAccountExpired="); 1087 buffer.append(deliverIfAccountExpired); 1088 1089 final Control[] controls = getControls(); 1090 if (controls.length > 0) 1091 { 1092 buffer.append(", controls={"); 1093 for (int i=0; i < controls.length; i++) 1094 { 1095 if (i > 0) 1096 { 1097 buffer.append(", "); 1098 } 1099 1100 buffer.append(controls[i]); 1101 } 1102 buffer.append('}'); 1103 } 1104 1105 buffer.append(')'); 1106 } 1107}